@@ -362,7 +362,7 @@ public void setUp() throws IOException {
362362 cleanupRule .register (InProcessChannelBuilder .forName (serverName ).directExecutor ().build ());
363363
364364 xdsServerInfo = ServerInfo .create (SERVER_URI , CHANNEL_CREDENTIALS , ignoreResourceDeletion (),
365- true , false );
365+ true , false , false );
366366 BootstrapInfo bootstrapInfo =
367367 Bootstrapper .BootstrapInfo .builder ()
368368 .servers (Collections .singletonList (xdsServerInfo ))
@@ -1448,6 +1448,66 @@ public void ldsResourceDeleted_ignoreResourceDeletion() {
14481448 verifyNoMoreInteractions (ldsResourceWatcher );
14491449 }
14501450
1451+ /**
1452+ * When fail_on_data_errors server feature is on, xDS client should delete the cached listener
1453+ * and fail RPCs when LDS resource is deleted.
1454+ */
1455+ @ Test
1456+ public void ldsResourceDeleted_failOnDataErrors () {
1457+ BootstrapperImpl .xdsDataErrorHandlingEnabled = true ;
1458+ xdsServerInfo = ServerInfo .create (SERVER_URI , CHANNEL_CREDENTIALS , false ,
1459+ true , false , true );
1460+ BootstrapInfo bootstrapInfo =
1461+ Bootstrapper .BootstrapInfo .builder ()
1462+ .servers (Collections .singletonList (xdsServerInfo ))
1463+ .node (NODE )
1464+ .authorities (ImmutableMap .of (
1465+ "" ,
1466+ AuthorityInfo .create (
1467+ "xdstp:///envoy.config.listener.v3.Listener/%s" ,
1468+ ImmutableList .of (Bootstrapper .ServerInfo .create (
1469+ SERVER_URI_EMPTY_AUTHORITY , CHANNEL_CREDENTIALS )))))
1470+ .certProviders (ImmutableMap .of ())
1471+ .build ();
1472+ xdsClient = new XdsClientImpl (
1473+ xdsTransportFactory ,
1474+ bootstrapInfo ,
1475+ fakeClock .getScheduledExecutorService (),
1476+ backoffPolicyProvider ,
1477+ fakeClock .getStopwatchSupplier (),
1478+ timeProvider ,
1479+ MessagePrinter .INSTANCE ,
1480+ new TlsContextManagerImpl (bootstrapInfo ),
1481+ xdsClientMetricReporter );
1482+
1483+ InOrder inOrder = inOrder (ldsResourceWatcher );
1484+ DiscoveryRpcCall call = startResourceWatcher (XdsListenerResource .getInstance (), LDS_RESOURCE ,
1485+ ldsResourceWatcher );
1486+ verifyResourceMetadataRequested (LDS , LDS_RESOURCE );
1487+
1488+ // Initial LDS response.
1489+ call .sendResponse (LDS , testListenerVhosts , VERSION_1 , "0000" );
1490+ call .verifyRequest (LDS , LDS_RESOURCE , VERSION_1 , "0000" , NODE );
1491+ inOrder .verify (ldsResourceWatcher ).onResourceChanged (ldsUpdateCaptor .capture ());
1492+ StatusOr <LdsUpdate > statusOrUpdate = ldsUpdateCaptor .getValue ();
1493+ assertThat (statusOrUpdate .hasValue ()).isTrue ();
1494+ verifyGoldenListenerVhosts (statusOrUpdate .getValue ());
1495+ verifyResourceMetadataAcked (LDS , LDS_RESOURCE , testListenerVhosts , VERSION_1 , TIME_INCREMENT );
1496+ verifySubscribedResourcesMetadataSizes (1 , 0 , 0 , 0 );
1497+
1498+ // Empty LDS response deletes the listener and fails RPCs.
1499+ call .sendResponse (LDS , Collections .<Any >emptyList (), VERSION_2 , "0001" );
1500+ call .verifyRequest (LDS , LDS_RESOURCE , VERSION_2 , "0001" , NODE );
1501+ inOrder .verify (ldsResourceWatcher ).onResourceChanged (ldsUpdateCaptor .capture ());
1502+ StatusOr <LdsUpdate > statusOrUpdate1 = ldsUpdateCaptor .getValue ();
1503+ assertThat (statusOrUpdate1 .hasValue ()).isFalse ();
1504+ assertThat (statusOrUpdate1 .getStatus ().getCode ()).isEqualTo (Status .Code .NOT_FOUND );
1505+ verifyResourceMetadataDoesNotExist (LDS , LDS_RESOURCE );
1506+ verifySubscribedResourcesMetadataSizes (1 , 0 , 0 , 0 );
1507+
1508+ BootstrapperImpl .xdsDataErrorHandlingEnabled = false ;
1509+ }
1510+
14511511 @ Test
14521512 @ SuppressWarnings ("unchecked" )
14531513 public void multipleLdsWatchers () {
@@ -2972,6 +3032,64 @@ public void cdsResourceDeleted_ignoreResourceDeletion() {
29723032 verifyNoMoreInteractions (ldsResourceWatcher );
29733033 }
29743034
3035+ /**
3036+ * When fail_on_data_errors server feature is on, xDS client should delete the cached cluster
3037+ * and fail RPCs when CDS resource is deleted.
3038+ */
3039+ @ Test
3040+ public void cdsResourceDeleted_failOnDataErrors () {
3041+ BootstrapperImpl .xdsDataErrorHandlingEnabled = true ;
3042+ xdsServerInfo = ServerInfo .create (SERVER_URI , CHANNEL_CREDENTIALS , false ,
3043+ true , false , true );
3044+ BootstrapInfo bootstrapInfo =
3045+ Bootstrapper .BootstrapInfo .builder ()
3046+ .servers (Collections .singletonList (xdsServerInfo ))
3047+ .node (NODE )
3048+ .authorities (ImmutableMap .of (
3049+ "" ,
3050+ AuthorityInfo .create (
3051+ "xdstp:///envoy.config.listener.v3.Listener/%s" ,
3052+ ImmutableList .of (Bootstrapper .ServerInfo .create (
3053+ SERVER_URI_EMPTY_AUTHORITY , CHANNEL_CREDENTIALS )))))
3054+ .certProviders (ImmutableMap .of ())
3055+ .build ();
3056+ xdsClient = new XdsClientImpl (
3057+ xdsTransportFactory ,
3058+ bootstrapInfo ,
3059+ fakeClock .getScheduledExecutorService (),
3060+ backoffPolicyProvider ,
3061+ fakeClock .getStopwatchSupplier (),
3062+ timeProvider ,
3063+ MessagePrinter .INSTANCE ,
3064+ new TlsContextManagerImpl (bootstrapInfo ),
3065+ xdsClientMetricReporter );
3066+
3067+ DiscoveryRpcCall call = startResourceWatcher (XdsClusterResource .getInstance (), CDS_RESOURCE ,
3068+ cdsResourceWatcher );
3069+ verifyResourceMetadataRequested (CDS , CDS_RESOURCE );
3070+
3071+ // Initial CDS response.
3072+ call .sendResponse (CDS , testClusterRoundRobin , VERSION_1 , "0000" );
3073+ call .verifyRequest (CDS , CDS_RESOURCE , VERSION_1 , "0000" , NODE );
3074+ verify (cdsResourceWatcher ).onResourceChanged (cdsUpdateCaptor .capture ());
3075+ StatusOr <CdsUpdate > statusOrUpdate = cdsUpdateCaptor .getValue ();
3076+ assertThat (statusOrUpdate .hasValue ()).isTrue ();
3077+ verifyGoldenClusterRoundRobin (statusOrUpdate .getValue ());
3078+ verifyResourceMetadataAcked (CDS , CDS_RESOURCE , testClusterRoundRobin , VERSION_1 ,
3079+ TIME_INCREMENT );
3080+ verifySubscribedResourcesMetadataSizes (0 , 1 , 0 , 0 );
3081+
3082+ // Empty CDS response deletes the cluster and fails RPCs.
3083+ call .sendResponse (CDS , Collections .<Any >emptyList (), VERSION_2 , "0001" );
3084+ call .verifyRequest (CDS , CDS_RESOURCE , VERSION_2 , "0001" , NODE );
3085+ verify (cdsResourceWatcher ).onResourceChanged (argThat (
3086+ arg -> !arg .hasValue () && arg .getStatus ().getDescription ().contains (CDS_RESOURCE )));
3087+ verifyResourceMetadataDoesNotExist (CDS , CDS_RESOURCE );
3088+ verifySubscribedResourcesMetadataSizes (0 , 1 , 0 , 0 );
3089+
3090+ BootstrapperImpl .xdsDataErrorHandlingEnabled = false ;
3091+ }
3092+
29753093 @ Test
29763094 @ SuppressWarnings ("unchecked" )
29773095 public void multipleCdsWatchers () {
@@ -3369,7 +3487,7 @@ public void flowControlAbsent() throws Exception {
33693487 public void resourceTimerIsTransientError_schedulesExtendedTimeout () {
33703488 BootstrapperImpl .xdsDataErrorHandlingEnabled = true ;
33713489 ServerInfo serverInfo = ServerInfo .create (SERVER_URI , CHANNEL_CREDENTIALS ,
3372- false , true , true );
3490+ false , true , true , false );
33733491 BootstrapInfo bootstrapInfo =
33743492 Bootstrapper .BootstrapInfo .builder ()
33753493 .servers (Collections .singletonList (serverInfo ))
@@ -3414,7 +3532,7 @@ public void resourceTimerIsTransientError_schedulesExtendedTimeout() {
34143532 public void resourceTimerIsTransientError_callsOnErrorUnavailable () {
34153533 BootstrapperImpl .xdsDataErrorHandlingEnabled = true ;
34163534 xdsServerInfo = ServerInfo .create (SERVER_URI , CHANNEL_CREDENTIALS , ignoreResourceDeletion (),
3417- true , true );
3535+ true , true , false );
34183536 BootstrapInfo bootstrapInfo =
34193537 Bootstrapper .BootstrapInfo .builder ()
34203538 .servers (Collections .singletonList (xdsServerInfo ))
@@ -4644,7 +4762,7 @@ private XdsClientImpl createXdsClient(String serverUri) {
46444762 private BootstrapInfo buildBootStrap (String serverUri ) {
46454763
46464764 ServerInfo xdsServerInfo = ServerInfo .create (serverUri , CHANNEL_CREDENTIALS ,
4647- ignoreResourceDeletion (), true , false );
4765+ ignoreResourceDeletion (), true , false , false );
46484766
46494767 return Bootstrapper .BootstrapInfo .builder ()
46504768 .servers (Collections .singletonList (xdsServerInfo ))
0 commit comments