8585import io .grpc .xds .client .Bootstrapper .BootstrapInfo ;
8686import io .grpc .xds .client .Bootstrapper .CertificateProviderInfo ;
8787import io .grpc .xds .client .Bootstrapper .ServerInfo ;
88+ import io .grpc .xds .client .BootstrapperImpl ;
8889import io .grpc .xds .client .EnvoyProtoData .Node ;
8990import io .grpc .xds .client .LoadStatsManager2 .ClusterDropStats ;
9091import io .grpc .xds .client .Locality ;
145146public abstract class GrpcXdsClientImplTestBase {
146147
147148 private static final String SERVER_URI = "trafficdirector.googleapis.com" ;
148- private static final String SERVER_URI_CUSTOME_AUTHORITY = "trafficdirector2.googleapis.com" ;
149+ private static final String SERVER_URI_CUSTOM_AUTHORITY = "trafficdirector2.googleapis.com" ;
149150 private static final String SERVER_URI_EMPTY_AUTHORITY = "trafficdirector3.googleapis.com" ;
150151 private static final String LDS_RESOURCE = "listener.googleapis.com" ;
151152 private static final String RDS_RESOURCE = "route-configuration.googleapis.com" ;
@@ -304,6 +305,30 @@ public long currentTimeNanos() {
304305 private final BindableService adsService = createAdsService ();
305306 private final BindableService lrsService = createLrsService ();
306307
308+ private XdsTransportFactory xdsTransportFactory = new XdsTransportFactory () {
309+ @ Override
310+ public XdsTransport create (ServerInfo serverInfo ) {
311+ if (serverInfo .target ().equals (SERVER_URI )) {
312+ return new GrpcXdsTransport (channel );
313+ }
314+ if (serverInfo .target ().equals (SERVER_URI_CUSTOM_AUTHORITY )) {
315+ if (channelForCustomAuthority == null ) {
316+ channelForCustomAuthority = cleanupRule .register (
317+ InProcessChannelBuilder .forName (serverName ).directExecutor ().build ());
318+ }
319+ return new GrpcXdsTransport (channelForCustomAuthority );
320+ }
321+ if (serverInfo .target ().equals (SERVER_URI_EMPTY_AUTHORITY )) {
322+ if (channelForEmptyAuthority == null ) {
323+ channelForEmptyAuthority = cleanupRule .register (
324+ InProcessChannelBuilder .forName (serverName ).directExecutor ().build ());
325+ }
326+ return new GrpcXdsTransport (channelForEmptyAuthority );
327+ }
328+ throw new IllegalArgumentException ("Can not create channel for " + serverInfo );
329+ }
330+ };
331+
307332 @ Before
308333 public void setUp () throws IOException {
309334 when (backoffPolicyProvider .get ()).thenReturn (backoffPolicy1 , backoffPolicy2 );
@@ -322,32 +347,9 @@ public void setUp() throws IOException {
322347 .start ());
323348 channel =
324349 cleanupRule .register (InProcessChannelBuilder .forName (serverName ).directExecutor ().build ());
325- XdsTransportFactory xdsTransportFactory = new XdsTransportFactory () {
326- @ Override
327- public XdsTransport create (ServerInfo serverInfo ) {
328- if (serverInfo .target ().equals (SERVER_URI )) {
329- return new GrpcXdsTransport (channel );
330- }
331- if (serverInfo .target ().equals (SERVER_URI_CUSTOME_AUTHORITY )) {
332- if (channelForCustomAuthority == null ) {
333- channelForCustomAuthority = cleanupRule .register (
334- InProcessChannelBuilder .forName (serverName ).directExecutor ().build ());
335- }
336- return new GrpcXdsTransport (channelForCustomAuthority );
337- }
338- if (serverInfo .target ().equals (SERVER_URI_EMPTY_AUTHORITY )) {
339- if (channelForEmptyAuthority == null ) {
340- channelForEmptyAuthority = cleanupRule .register (
341- InProcessChannelBuilder .forName (serverName ).directExecutor ().build ());
342- }
343- return new GrpcXdsTransport (channelForEmptyAuthority );
344- }
345- throw new IllegalArgumentException ("Can not create channel for " + serverInfo );
346- }
347- };
348350
349351 xdsServerInfo = ServerInfo .create (SERVER_URI , CHANNEL_CREDENTIALS , ignoreResourceDeletion (),
350- true );
352+ true , false );
351353 BootstrapInfo bootstrapInfo =
352354 Bootstrapper .BootstrapInfo .builder ()
353355 .servers (Collections .singletonList (xdsServerInfo ))
@@ -357,7 +359,7 @@ public XdsTransport create(ServerInfo serverInfo) {
357359 AuthorityInfo .create (
358360 "xdstp://authority.xds.com/envoy.config.listener.v3.Listener/%s" ,
359361 ImmutableList .of (Bootstrapper .ServerInfo .create (
360- SERVER_URI_CUSTOME_AUTHORITY , CHANNEL_CREDENTIALS ))),
362+ SERVER_URI_CUSTOM_AUTHORITY , CHANNEL_CREDENTIALS ))),
361363 "" ,
362364 AuthorityInfo .create (
363365 "xdstp:///envoy.config.listener.v3.Listener/%s" ,
@@ -3155,6 +3157,108 @@ public void flowControlAbsent() throws Exception {
31553157 verify (anotherWatcher ).onError (any ());
31563158 }
31573159
3160+ @ Test
3161+ @ SuppressWarnings ("unchecked" )
3162+ public void resourceTimerIsTransientError_schedulesExtendedTimeout () {
3163+ BootstrapperImpl .xdsDataErrorHandlingEnabled = true ;
3164+ ServerInfo serverInfo = ServerInfo .create (SERVER_URI , CHANNEL_CREDENTIALS ,
3165+ false , true , true );
3166+ BootstrapInfo bootstrapInfo =
3167+ Bootstrapper .BootstrapInfo .builder ()
3168+ .servers (Collections .singletonList (serverInfo ))
3169+ .node (NODE )
3170+ .authorities (ImmutableMap .of (
3171+ "" ,
3172+ AuthorityInfo .create (
3173+ "xdstp:///envoy.config.listener.v3.Listener/%s" ,
3174+ ImmutableList .of (Bootstrapper .ServerInfo .create (
3175+ SERVER_URI_EMPTY_AUTHORITY , CHANNEL_CREDENTIALS )))))
3176+ .certProviders (ImmutableMap .of ())
3177+ .build ();
3178+ xdsClient = new XdsClientImpl (
3179+ xdsTransportFactory ,
3180+ bootstrapInfo ,
3181+ fakeClock .getScheduledExecutorService (),
3182+ backoffPolicyProvider ,
3183+ fakeClock .getStopwatchSupplier (),
3184+ timeProvider ,
3185+ MessagePrinter .INSTANCE ,
3186+ new TlsContextManagerImpl (bootstrapInfo ),
3187+ xdsClientMetricReporter );
3188+ ResourceWatcher <CdsUpdate > watcher = mock (ResourceWatcher .class );
3189+ String resourceName = "cluster.googleapis.com" ;
3190+
3191+ xdsClient .watchXdsResource (
3192+ XdsClusterResource .getInstance (),
3193+ resourceName ,
3194+ watcher ,
3195+ fakeClock .getScheduledExecutorService ());
3196+
3197+ ScheduledTask task = Iterables .getOnlyElement (
3198+ fakeClock .getPendingTasks (CDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER ));
3199+ assertThat (task .getDelay (TimeUnit .SECONDS ))
3200+ .isEqualTo (XdsClientImpl .EXTENDED_RESOURCE_FETCH_TIMEOUT_SEC );
3201+ fakeClock .runDueTasks ();
3202+ BootstrapperImpl .xdsDataErrorHandlingEnabled = false ;
3203+ }
3204+
3205+ @ Test
3206+ @ SuppressWarnings ("unchecked" )
3207+ public void resourceTimerIsTransientError_callsOnErrorUnavailable () {
3208+ BootstrapperImpl .xdsDataErrorHandlingEnabled = true ;
3209+ xdsServerInfo = ServerInfo .create (SERVER_URI , CHANNEL_CREDENTIALS , ignoreResourceDeletion (),
3210+ true , true );
3211+ BootstrapInfo bootstrapInfo =
3212+ Bootstrapper .BootstrapInfo .builder ()
3213+ .servers (Collections .singletonList (xdsServerInfo ))
3214+ .node (NODE )
3215+ .authorities (ImmutableMap .of (
3216+ "authority.xds.com" ,
3217+ AuthorityInfo .create (
3218+ "xdstp://authority.xds.com/envoy.config.listener.v3.Listener/%s" ,
3219+ ImmutableList .of (Bootstrapper .ServerInfo .create (
3220+ SERVER_URI_CUSTOM_AUTHORITY , CHANNEL_CREDENTIALS ))),
3221+ "" ,
3222+ AuthorityInfo .create (
3223+ "xdstp:///envoy.config.listener.v3.Listener/%s" ,
3224+ ImmutableList .of (Bootstrapper .ServerInfo .create (
3225+ SERVER_URI_EMPTY_AUTHORITY , CHANNEL_CREDENTIALS )))))
3226+ .certProviders (ImmutableMap .of ("cert-instance-name" ,
3227+ CertificateProviderInfo .create ("file-watcher" , ImmutableMap .of ())))
3228+ .build ();
3229+ xdsClient = new XdsClientImpl (
3230+ xdsTransportFactory ,
3231+ bootstrapInfo ,
3232+ fakeClock .getScheduledExecutorService (),
3233+ backoffPolicyProvider ,
3234+ fakeClock .getStopwatchSupplier (),
3235+ timeProvider ,
3236+ MessagePrinter .INSTANCE ,
3237+ new TlsContextManagerImpl (bootstrapInfo ),
3238+ xdsClientMetricReporter );
3239+ String timeoutResource = CDS_RESOURCE + "_timeout" ;
3240+ ResourceWatcher <CdsUpdate > timeoutWatcher = mock (ResourceWatcher .class );
3241+
3242+ xdsClient .watchXdsResource (
3243+ XdsClusterResource .getInstance (),
3244+ timeoutResource ,
3245+ timeoutWatcher ,
3246+ fakeClock .getScheduledExecutorService ());
3247+
3248+ assertThat (resourceDiscoveryCalls ).hasSize (1 );
3249+ DiscoveryRpcCall call = resourceDiscoveryCalls .poll ();
3250+ call .verifyRequest (CDS , ImmutableList .of (timeoutResource ), "" , "" , NODE );
3251+ fakeClock .forwardTime (XdsClientImpl .EXTENDED_RESOURCE_FETCH_TIMEOUT_SEC , TimeUnit .SECONDS );
3252+ fakeClock .runDueTasks ();
3253+ ArgumentCaptor <Status > errorCaptor = ArgumentCaptor .forClass (Status .class );
3254+ verify (timeoutWatcher ).onError (errorCaptor .capture ());
3255+ Status error = errorCaptor .getValue ();
3256+ assertThat (error .getCode ()).isEqualTo (Status .Code .UNAVAILABLE );
3257+ assertThat (error .getDescription ()).isEqualTo (
3258+ "Timed out waiting for resource " + timeoutResource + " from xDS server" );
3259+ BootstrapperImpl .xdsDataErrorHandlingEnabled = false ;
3260+ }
3261+
31583262 private Answer <Void > blockUpdate (CyclicBarrier barrier ) {
31593263 return new Answer <Void >() {
31603264 @ Override
@@ -4220,7 +4324,7 @@ private XdsClientImpl createXdsClient(String serverUri) {
42204324 private BootstrapInfo buildBootStrap (String serverUri ) {
42214325
42224326 ServerInfo xdsServerInfo = ServerInfo .create (serverUri , CHANNEL_CREDENTIALS ,
4223- ignoreResourceDeletion (), true );
4327+ ignoreResourceDeletion (), true , false );
42244328
42254329 return Bootstrapper .BootstrapInfo .builder ()
42264330 .servers (Collections .singletonList (xdsServerInfo ))
@@ -4230,7 +4334,7 @@ private BootstrapInfo buildBootStrap(String serverUri) {
42304334 AuthorityInfo .create (
42314335 "xdstp://authority.xds.com/envoy.config.listener.v3.Listener/%s" ,
42324336 ImmutableList .of (Bootstrapper .ServerInfo .create (
4233- SERVER_URI_CUSTOME_AUTHORITY , CHANNEL_CREDENTIALS ))),
4337+ SERVER_URI_CUSTOM_AUTHORITY , CHANNEL_CREDENTIALS ))),
42344338 "" ,
42354339 AuthorityInfo .create (
42364340 "xdstp:///envoy.config.listener.v3.Listener/%s" ,
0 commit comments