1818
1919import static com .google .common .truth .Truth .assertThat ;
2020import static com .google .common .truth .Truth .assertWithMessage ;
21+ import static io .grpc .xds .XdsClientImpl .XdsChannelFactory .DEFAULT_XDS_CHANNEL_FACTORY ;
2122import static org .mockito .ArgumentMatchers .any ;
2223import static org .mockito .ArgumentMatchers .isA ;
2324import static org .mockito .Mockito .mock ;
7071import io .grpc .stub .StreamObserver ;
7172import io .grpc .testing .GrpcCleanupRule ;
7273import io .grpc .xds .Bootstrapper .AuthorityInfo ;
74+ import io .grpc .xds .Bootstrapper .BootstrapInfo ;
7375import io .grpc .xds .Bootstrapper .CertificateProviderInfo ;
7476import io .grpc .xds .Bootstrapper .ServerInfo ;
7577import io .grpc .xds .Endpoints .DropOverload ;
114116import org .junit .runner .RunWith ;
115117import org .junit .runners .JUnit4 ;
116118import org .mockito .ArgumentCaptor ;
119+ import org .mockito .ArgumentMatchers ;
117120import org .mockito .Captor ;
118121import org .mockito .InOrder ;
119122import org .mockito .Mock ;
@@ -3226,7 +3229,8 @@ public void streamClosedAndRetryWithBackoff() {
32263229
32273230 // Management server closes the RPC stream with an error.
32283231 call .sendError (Status .UNKNOWN .asException ());
3229- verify (ldsResourceWatcher ).onError (errorCaptor .capture ());
3232+ verify (ldsResourceWatcher , Mockito .timeout (1000 ).times (1 ))
3233+ .onError (errorCaptor .capture ());
32303234 verifyStatusWithNodeId (errorCaptor .getValue (), Code .UNKNOWN , "" );
32313235 verify (rdsResourceWatcher ).onError (errorCaptor .capture ());
32323236 verifyStatusWithNodeId (errorCaptor .getValue (), Code .UNKNOWN , "" );
@@ -3336,7 +3340,8 @@ public void streamClosedAndRetryRaceWithAddRemoveWatchers() {
33363340 RDS_RESOURCE , rdsResourceWatcher );
33373341 DiscoveryRpcCall call = resourceDiscoveryCalls .poll ();
33383342 call .sendError (Status .UNAVAILABLE .asException ());
3339- verify (ldsResourceWatcher ).onError (errorCaptor .capture ());
3343+ verify (ldsResourceWatcher , Mockito .timeout (1000 ).times (1 ))
3344+ .onError (errorCaptor .capture ());
33403345 verifyStatusWithNodeId (errorCaptor .getValue (), Code .UNAVAILABLE , "" );
33413346 verify (rdsResourceWatcher ).onError (errorCaptor .capture ());
33423347 verifyStatusWithNodeId (errorCaptor .getValue (), Code .UNAVAILABLE , "" );
@@ -3573,13 +3578,18 @@ public void sendingToStoppedServer() throws Exception {
35733578 .build ()
35743579 .start ());
35753580 fakeClock .forwardTime (5 , TimeUnit .SECONDS );
3581+ verify (ldsResourceWatcher , never ()).onResourceDoesNotExist (LDS_RESOURCE );
3582+ fakeClock .forwardTime (20 , TimeUnit .SECONDS ); // Trigger rpcRetryTimer
35763583 DiscoveryRpcCall call = resourceDiscoveryCalls .poll (3 , TimeUnit .SECONDS );
3584+ if (call == null ) { // The first rpcRetry may have happened before the channel was ready
3585+ fakeClock .forwardTime (50 , TimeUnit .SECONDS );
3586+ call = resourceDiscoveryCalls .poll (3 , TimeUnit .SECONDS );
3587+ }
35773588
35783589 // NOTE: There is a ScheduledExecutorService that may get involved due to the reconnect
35793590 // so you cannot rely on the logic being single threaded. The timeout() in verifyRequest
35803591 // is therefore necessary to avoid flakiness.
35813592 // Send a response and do verifications
3582- verify (ldsResourceWatcher , never ()).onResourceDoesNotExist (LDS_RESOURCE );
35833593 call .sendResponse (LDS , mf .buildWrappedResource (testListenerVhosts ), VERSION_1 , "0001" );
35843594 call .verifyRequest (LDS , LDS_RESOURCE , VERSION_1 , "0001" , NODE );
35853595 verify (ldsResourceWatcher ).onChanged (ldsUpdateCaptor .capture ());
@@ -3592,6 +3602,66 @@ public void sendingToStoppedServer() throws Exception {
35923602 }
35933603 }
35943604
3605+ @ Test
3606+ public void sendToBadUrl () throws Exception {
3607+ // Setup xdsClient to fail on stream creation
3608+ XdsClientImpl client = createXdsClient ("some. garbage" );
3609+
3610+ client .watchXdsResource (XdsListenerResource .getInstance (), LDS_RESOURCE , ldsResourceWatcher );
3611+ fakeClock .forwardTime (20 , TimeUnit .SECONDS );
3612+ verify (ldsResourceWatcher , Mockito .timeout (5000 ).times (1 )).onError (ArgumentMatchers .any ());
3613+ client .shutdown ();
3614+ }
3615+
3616+ @ Test
3617+ public void sendToNonexistentHost () throws Exception {
3618+ // Setup xdsClient to fail on stream creation
3619+ XdsClientImpl client = createXdsClient ("some.garbage" );
3620+ client .watchXdsResource (XdsListenerResource .getInstance (), LDS_RESOURCE , ldsResourceWatcher );
3621+ fakeClock .forwardTime (20 , TimeUnit .SECONDS );
3622+
3623+ verify (ldsResourceWatcher , Mockito .timeout (5000 ).times (1 )).onError (ArgumentMatchers .any ());
3624+ fakeClock .forwardTime (50 , TimeUnit .SECONDS ); // Trigger rpcRetry if appropriate
3625+ assertThat (fakeClock .getPendingTasks (LDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER )).isEmpty ();
3626+ client .shutdown ();
3627+ }
3628+
3629+ private XdsClientImpl createXdsClient (String serverUri ) {
3630+ BootstrapInfo bootstrapInfo = buildBootStrap (serverUri );
3631+ return new XdsClientImpl (
3632+ DEFAULT_XDS_CHANNEL_FACTORY ,
3633+ bootstrapInfo ,
3634+ Context .ROOT ,
3635+ fakeClock .getScheduledExecutorService (),
3636+ backoffPolicyProvider ,
3637+ fakeClock .getStopwatchSupplier (),
3638+ timeProvider ,
3639+ tlsContextManager );
3640+ }
3641+
3642+ private BootstrapInfo buildBootStrap (String serverUri ) {
3643+
3644+ ServerInfo xdsServerInfo = ServerInfo .create (serverUri , CHANNEL_CREDENTIALS ,
3645+ ignoreResourceDeletion ());
3646+
3647+ return Bootstrapper .BootstrapInfo .builder ()
3648+ .servers (Collections .singletonList (xdsServerInfo ))
3649+ .node (NODE )
3650+ .authorities (ImmutableMap .of (
3651+ "authority.xds.com" ,
3652+ AuthorityInfo .create (
3653+ "xdstp://authority.xds.com/envoy.config.listener.v3.Listener/%s" ,
3654+ ImmutableList .of (Bootstrapper .ServerInfo .create (
3655+ SERVER_URI_CUSTOME_AUTHORITY , CHANNEL_CREDENTIALS ))),
3656+ "" ,
3657+ AuthorityInfo .create (
3658+ "xdstp:///envoy.config.listener.v3.Listener/%s" ,
3659+ ImmutableList .of (Bootstrapper .ServerInfo .create (
3660+ SERVER_URI_EMPTY_AUTHORITY , CHANNEL_CREDENTIALS )))))
3661+ .certProviders (ImmutableMap .of ("cert-instance-name" ,
3662+ CertificateProviderInfo .create ("file-watcher" , ImmutableMap .<String , Object >of ())))
3663+ .build ();
3664+ }
35953665
35963666 private <T extends ResourceUpdate > DiscoveryRpcCall startResourceWatcher (
35973667 XdsResourceType <T > type , String name , ResourceWatcher <T > watcher ) {
0 commit comments