@@ -1433,7 +1433,105 @@ public void VerifyRegionExcludedTest(
14331433
14341434 }
14351435
1436- [ TestMethod ]
1436+ /// <summary>
1437+ /// Validates that when all preferred regions are included in ExcludeRegions, read requests fall
1438+ /// back to the configured default (Hub) endpoint unconditionally — even when that endpoint has
1439+ /// been marked as unavailable. The unavailability tracking used by the normal ReadEndpoints
1440+ /// ordering does NOT intercept the ExcludeRegions fallback path inside GetApplicableEndpoints.
1441+ /// </summary>
1442+ [ TestMethod ]
1443+ [ DataRow ( false , false , DisplayName = "All regions excluded - global default endpoint - default endpoint is available" ) ]
1444+ [ DataRow ( false , true , DisplayName = "All regions excluded - global default endpoint - default endpoint is also marked unavailable" ) ]
1445+ [ DataRow ( true , false , DisplayName = "All regions excluded - regional default endpoint - default endpoint is available" ) ]
1446+ [ DataRow ( true , true , DisplayName = "All regions excluded - regional default endpoint - default endpoint is also marked unavailable" ) ]
1447+ public void ValidateFallbackToDefaultEndpointWhenAllRegionsExcluded (
1448+ bool isDefaultEndpointARegionalEndpoint ,
1449+ bool markDefaultEndpointUnavailable )
1450+ {
1451+ // The hub/configured endpoint — a global URI when not regional, a regional URI otherwise.
1452+ Uri defaultEndpoint = isDefaultEndpointARegionalEndpoint
1453+ ? new Uri ( "https://location1.documents.azure.com" )
1454+ : new Uri ( "https://testaccount.documents.azure.com" ) ;
1455+
1456+ Collection < AccountRegion > readLocations = new Collection < AccountRegion > ( )
1457+ {
1458+ new AccountRegion { Name = "location1" , Endpoint = "https://location1.documents.azure.com" } ,
1459+ new AccountRegion { Name = "location2" , Endpoint = "https://location2.documents.azure.com" } ,
1460+ new AccountRegion { Name = "location3" , Endpoint = "https://location3.documents.azure.com" } ,
1461+ } ;
1462+
1463+ Collection < AccountRegion > writeLocations = new Collection < AccountRegion > ( )
1464+ {
1465+ new AccountRegion { Name = "location1" , Endpoint = "https://location1.documents.azure.com" } ,
1466+ } ;
1467+
1468+ AccountProperties accountProps = new AccountProperties
1469+ {
1470+ ReadLocationsInternal = readLocations ,
1471+ WriteLocationsInternal = writeLocations ,
1472+ EnableMultipleWriteLocations = false ,
1473+ } ;
1474+
1475+ ReadOnlyCollection < string > preferredLocations = new List < string >
1476+ {
1477+ "location1" ,
1478+ "location2" ,
1479+ "location3" ,
1480+ } . AsReadOnly ( ) ;
1481+
1482+ LocationCache cache = new LocationCache (
1483+ preferredLocations : preferredLocations ,
1484+ defaultEndpoint : defaultEndpoint ,
1485+ enableEndpointDiscovery : true ,
1486+ connectionLimit : 10 ,
1487+ useMultipleWriteLocations : false ) ;
1488+
1489+ cache . OnDatabaseAccountRead ( accountProps ) ;
1490+
1491+ // Sanity check: before excluding any region the preferred read endpoints are the named regions.
1492+ Assert . IsTrue ( cache . ReadEndpoints . Count > 0 , "There should be read endpoints before any exclusion." ) ;
1493+ if ( ! isDefaultEndpointARegionalEndpoint )
1494+ {
1495+ // When defaultEndpoint is a global (non-regional) URI it should not appear in the
1496+ // named-region read-endpoint list.
1497+ Assert . IsFalse ( cache . ReadEndpoints . Contains ( defaultEndpoint ) ,
1498+ "The global default endpoint should not appear in the ordered read-endpoint list when named regions are available." ) ;
1499+ }
1500+
1501+ if ( markDefaultEndpointUnavailable )
1502+ {
1503+ // Mark the hub/default endpoint unavailable for reads to confirm the ExcludeRegions
1504+ // fallback is unconditional and does not consult the unavailability registry.
1505+ cache . MarkEndpointUnavailableForRead ( defaultEndpoint ) ;
1506+ }
1507+
1508+ // Exclude every named region so that no applicable endpoint survives filtering.
1509+ List < string > allRegions = new List < string > { "location1" , "location2" , "location3" } ;
1510+
1511+ using ( DocumentServiceRequest request = DocumentServiceRequest . Create (
1512+ OperationType . Read ,
1513+ ResourceType . Document ,
1514+ AuthorizationTokenType . PrimaryMasterKey ) )
1515+ {
1516+ request . RequestContext . ExcludeRegions = allRegions ;
1517+
1518+ // GetApplicableEndpoints must fall back to the configured default endpoint when every
1519+ // preferred region is excluded, regardless of the endpoint's own availability status.
1520+ ReadOnlyCollection < Uri > applicableEndpoints = cache . GetApplicableEndpoints ( request , isReadRequest : true ) ;
1521+
1522+ Assert . AreEqual ( 1 , applicableEndpoints . Count ,
1523+ "Exactly one fallback endpoint should be returned when all regions are excluded." ) ;
1524+ Assert . AreEqual ( defaultEndpoint , applicableEndpoints [ 0 ] ,
1525+ "The fallback endpoint must be the configured default/Hub endpoint, even if it is marked unavailable." ) ;
1526+
1527+ // ResolveServiceEndpoint must also route the request to that same default endpoint.
1528+ Uri resolvedEndpoint = cache . ResolveServiceEndpoint ( request ) ;
1529+ Assert . AreEqual ( defaultEndpoint , resolvedEndpoint ,
1530+ "ResolveServiceEndpoint must route to the default/Hub endpoint when all regions are excluded." ) ;
1531+ }
1532+ }
1533+
1534+ [ TestMethod ]
14371535 public void ValidateThinClientReadFallbackToWriteEndpointTest ( )
14381536 {
14391537 // Arrange:
0 commit comments