1717package io .grpc .internal ;
1818
1919import static com .google .common .truth .Truth .assertThat ;
20+ import static org .junit .Assert .fail ;
2021import static org .mockito .ArgumentMatchers .isA ;
2122import static org .mockito .Mockito .verify ;
2223
2324import io .grpc .NameResolver ;
2425import io .grpc .NameResolver .Listener2 ;
2526import io .grpc .NameResolver .ResolutionResult ;
27+ import io .grpc .Status ;
2628import io .grpc .internal .RetryingNameResolver .ResolutionResultListener ;
2729import org .junit .Before ;
2830import org .junit .Rule ;
@@ -53,7 +55,7 @@ public class RetryingNameResolverTest {
5355 @ Captor
5456 private ArgumentCaptor <Listener2 > listenerCaptor ;
5557 @ Captor
56- private ArgumentCaptor <ResolutionResult > resolutionResultCaptor ;
58+ private ArgumentCaptor <ResolutionResult > onResultCaptor ;
5759
5860 private RetryingNameResolver retryingNameResolver ;
5961
@@ -69,15 +71,15 @@ public void startAndShutdown() {
6971 }
7072
7173 // Make sure the ResolutionResultListener callback is added to the ResolutionResult attributes,
72- // and the retry scheduler is reset since the name resolution was successful..
74+ // and the retry scheduler is reset since the name resolution was successful.
7375 @ Test
7476 public void onResult_sucess () {
7577 retryingNameResolver .start (mockListener );
7678 verify (mockNameResolver ).start (listenerCaptor .capture ());
7779
7880 listenerCaptor .getValue ().onResult (ResolutionResult .newBuilder ().build ());
79- verify (mockListener ).onResult (resolutionResultCaptor .capture ());
80- ResolutionResultListener resolutionResultListener = resolutionResultCaptor .getValue ()
81+ verify (mockListener ).onResult (onResultCaptor .capture ());
82+ ResolutionResultListener resolutionResultListener = onResultCaptor .getValue ()
8183 .getAttributes ()
8284 .get (RetryingNameResolver .RESOLUTION_RESULT_LISTENER_KEY );
8385 assertThat (resolutionResultListener ).isNotNull ();
@@ -87,15 +89,15 @@ public void onResult_sucess() {
8789 }
8890
8991 // Make sure the ResolutionResultListener callback is added to the ResolutionResult attributes,
90- // and the retry scheduler is reset since the name resolution was successful. .
92+ // and that a retry gets scheduled when the resolution results are rejected .
9193 @ Test
9294 public void onResult_failure () {
9395 retryingNameResolver .start (mockListener );
9496 verify (mockNameResolver ).start (listenerCaptor .capture ());
9597
9698 listenerCaptor .getValue ().onResult (ResolutionResult .newBuilder ().build ());
97- verify (mockListener ).onResult (resolutionResultCaptor .capture ());
98- ResolutionResultListener resolutionResultListener = resolutionResultCaptor .getValue ()
99+ verify (mockListener ).onResult (onResultCaptor .capture ());
100+ ResolutionResultListener resolutionResultListener = onResultCaptor .getValue ()
99101 .getAttributes ()
100102 .get (RetryingNameResolver .RESOLUTION_RESULT_LISTENER_KEY );
101103 assertThat (resolutionResultListener ).isNotNull ();
@@ -104,8 +106,31 @@ public void onResult_failure() {
104106 verify (mockRetryScheduler ).schedule (isA (Runnable .class ));
105107 }
106108
109+ // Wrapping a NameResolver more than once is a misconfiguration.
107110 @ Test
108- public void onError () {
111+ public void onResult_failure_doubleWrapped () {
112+ NameResolver doubleWrappedResolver = new RetryingNameResolver (retryingNameResolver ,
113+ mockRetryScheduler );
114+
115+ doubleWrappedResolver .start (mockListener );
116+ verify (mockNameResolver ).start (listenerCaptor .capture ());
117+
118+ try {
119+ listenerCaptor .getValue ().onResult (ResolutionResult .newBuilder ().build ());
120+ } catch (IllegalStateException e ) {
121+ assertThat (e ).hasMessageThat ().contains ("can only be used once" );
122+ return ;
123+ }
124+ fail ("An exception should have been thrown for a double wrapped NAmeResolver" );
125+ }
109126
127+ // A retry should get scheduled when name resolution fails.
128+ @ Test
129+ public void onError () {
130+ retryingNameResolver .start (mockListener );
131+ verify (mockNameResolver ).start (listenerCaptor .capture ());
132+ listenerCaptor .getValue ().onError (Status .DEADLINE_EXCEEDED );
133+ verify (mockListener ).onError (Status .DEADLINE_EXCEEDED );
134+ verify (mockRetryScheduler ).schedule (isA (Runnable .class ));
110135 }
111136}
0 commit comments