30
30
package com .google .api .gax .grpc ;
31
31
32
32
import static com .google .common .truth .Truth .assertThat ;
33
+ import static org .junit .Assert .assertThrows ;
33
34
import static org .mockito .Mockito .verify ;
34
35
35
36
import com .google .api .gax .grpc .testing .FakeChannelFactory ;
36
37
import com .google .api .gax .grpc .testing .FakeServiceGrpc ;
38
+ import com .google .api .gax .rpc .EndpointContext ;
39
+ import com .google .api .gax .rpc .UnauthenticatedException ;
40
+ import com .google .api .gax .rpc .UnavailableException ;
41
+ import com .google .auth .Credentials ;
42
+ import com .google .auth .Retryable ;
37
43
import com .google .common .collect .ImmutableList ;
38
44
import com .google .common .truth .Truth ;
39
45
import com .google .type .Color ;
45
51
import io .grpc .ManagedChannel ;
46
52
import io .grpc .Metadata ;
47
53
import io .grpc .MethodDescriptor ;
54
+ import io .grpc .Status ;
48
55
import java .io .IOException ;
49
56
import java .util .Arrays ;
50
57
import java .util .HashMap ;
51
58
import java .util .List ;
52
59
import java .util .Map ;
53
60
import java .util .concurrent .TimeUnit ;
61
+ import org .junit .Before ;
54
62
import org .junit .Test ;
55
63
import org .mockito .ArgumentCaptor ;
56
64
import org .mockito .Mockito ;
57
65
import org .threeten .bp .Duration ;
58
66
59
67
public class GrpcClientCallsTest {
68
+
69
+ // Auth Library's GoogleAuthException is package-private. Copy basic functionality for tests
70
+ private static class GoogleAuthException extends IOException implements Retryable {
71
+
72
+ private final boolean isRetryable ;
73
+
74
+ private GoogleAuthException (boolean isRetryable ) {
75
+ this .isRetryable = isRetryable ;
76
+ }
77
+
78
+ @ Override
79
+ public boolean isRetryable () {
80
+ return isRetryable ;
81
+ }
82
+
83
+ @ Override
84
+ public int getRetryCount () {
85
+ return 0 ;
86
+ }
87
+ }
88
+
89
+ private GrpcCallContext defaultCallContext ;
90
+ private EndpointContext endpointContext ;
91
+ private Credentials credentials ;
92
+ private Channel mockChannel ;
93
+
94
+ @ Before
95
+ public void setUp () throws IOException {
96
+ credentials = Mockito .mock (Credentials .class );
97
+ endpointContext = Mockito .mock (EndpointContext .class );
98
+ mockChannel = Mockito .mock (Channel .class );
99
+
100
+ defaultCallContext = GrpcCallContext .createDefault ().withEndpointContext (endpointContext );
101
+ Mockito .doNothing ()
102
+ .when (endpointContext )
103
+ .validateUniverseDomain (Mockito .any (Credentials .class ), Mockito .any (GrpcStatusCode .class ));
104
+ }
105
+
60
106
@ Test
61
107
public void testAffinity () throws IOException {
62
108
MethodDescriptor <Color , Money > descriptor = FakeServiceGrpc .METHOD_RECOGNIZE ;
@@ -78,7 +124,7 @@ public void testAffinity() throws IOException {
78
124
ChannelPool .create (
79
125
ChannelPoolSettings .staticallySized (2 ),
80
126
new FakeChannelFactory (Arrays .asList (channel0 , channel1 )));
81
- GrpcCallContext context = GrpcCallContext . createDefault () .withChannel (pool );
127
+ GrpcCallContext context = defaultCallContext .withChannel (pool );
82
128
83
129
ClientCall <Color , Money > gotCallA =
84
130
GrpcClientCalls .newCall (descriptor , context .withChannelAffinity (0 ));
@@ -92,7 +138,7 @@ public void testAffinity() throws IOException {
92
138
}
93
139
94
140
@ Test
95
- public void testExtraHeaders () {
141
+ public void testExtraHeaders () throws IOException {
96
142
Metadata emptyHeaders = new Metadata ();
97
143
final Map <String , List <String >> extraHeaders = new HashMap <>();
98
144
extraHeaders .put (
@@ -128,12 +174,12 @@ public void testExtraHeaders() {
128
174
.thenReturn (mockClientCall );
129
175
130
176
GrpcCallContext context =
131
- GrpcCallContext . createDefault () .withChannel (mockChannel ).withExtraHeaders (extraHeaders );
177
+ defaultCallContext .withChannel (mockChannel ).withExtraHeaders (extraHeaders );
132
178
GrpcClientCalls .newCall (descriptor , context ).start (mockListener , emptyHeaders );
133
179
}
134
180
135
181
@ Test
136
- public void testTimeoutToDeadlineConversion () {
182
+ public void testTimeoutToDeadlineConversion () throws IOException {
137
183
MethodDescriptor <Color , Money > descriptor = FakeServiceGrpc .METHOD_RECOGNIZE ;
138
184
139
185
@ SuppressWarnings ("unchecked" )
@@ -152,8 +198,7 @@ public void testTimeoutToDeadlineConversion() {
152
198
Duration timeout = Duration .ofSeconds (10 );
153
199
Deadline minExpectedDeadline = Deadline .after (timeout .getSeconds (), TimeUnit .SECONDS );
154
200
155
- GrpcCallContext context =
156
- GrpcCallContext .createDefault ().withChannel (mockChannel ).withTimeout (timeout );
201
+ GrpcCallContext context = defaultCallContext .withChannel (mockChannel ).withTimeout (timeout );
157
202
158
203
GrpcClientCalls .newCall (descriptor , context ).start (mockListener , new Metadata ());
159
204
@@ -164,7 +209,7 @@ public void testTimeoutToDeadlineConversion() {
164
209
}
165
210
166
211
@ Test
167
- public void testTimeoutAfterDeadline () {
212
+ public void testTimeoutAfterDeadline () throws IOException {
168
213
MethodDescriptor <Color , Money > descriptor = FakeServiceGrpc .METHOD_RECOGNIZE ;
169
214
170
215
@ SuppressWarnings ("unchecked" )
@@ -185,7 +230,7 @@ public void testTimeoutAfterDeadline() {
185
230
Duration timeout = Duration .ofSeconds (10 );
186
231
187
232
GrpcCallContext context =
188
- GrpcCallContext . createDefault ()
233
+ defaultCallContext
189
234
.withChannel (mockChannel )
190
235
.withCallOptions (CallOptions .DEFAULT .withDeadline (priorDeadline ))
191
236
.withTimeout (timeout );
@@ -197,7 +242,7 @@ public void testTimeoutAfterDeadline() {
197
242
}
198
243
199
244
@ Test
200
- public void testTimeoutBeforeDeadline () {
245
+ public void testTimeoutBeforeDeadline () throws IOException {
201
246
MethodDescriptor <Color , Money > descriptor = FakeServiceGrpc .METHOD_RECOGNIZE ;
202
247
203
248
@ SuppressWarnings ("unchecked" )
@@ -219,7 +264,7 @@ public void testTimeoutBeforeDeadline() {
219
264
Deadline minExpectedDeadline = Deadline .after (timeout .getSeconds (), TimeUnit .SECONDS );
220
265
221
266
GrpcCallContext context =
222
- GrpcCallContext . createDefault ()
267
+ defaultCallContext
223
268
.withChannel (mockChannel )
224
269
.withCallOptions (CallOptions .DEFAULT .withDeadline (subsequentDeadline ))
225
270
.withTimeout (timeout );
@@ -232,4 +277,66 @@ public void testTimeoutBeforeDeadline() {
232
277
Truth .assertThat (capturedCallOptions .getValue ().getDeadline ()).isAtLeast (minExpectedDeadline );
233
278
Truth .assertThat (capturedCallOptions .getValue ().getDeadline ()).isAtMost (maxExpectedDeadline );
234
279
}
280
+
281
+ @ Test
282
+ public void testValidUniverseDomain () throws IOException {
283
+ GrpcCallContext context =
284
+ GrpcCallContext .createDefault ()
285
+ .withChannel (mockChannel )
286
+ .withCredentials (credentials )
287
+ .withEndpointContext (endpointContext );
288
+
289
+ CallOptions callOptions = context .getCallOptions ();
290
+
291
+ MethodDescriptor <Color , Money > descriptor = FakeServiceGrpc .METHOD_RECOGNIZE ;
292
+ GrpcClientCalls .newCall (descriptor , context );
293
+ Mockito .verify (mockChannel , Mockito .times (1 )).newCall (descriptor , callOptions );
294
+ }
295
+
296
+ // This test is when the universe domain does not match
297
+ @ Test
298
+ public void testInvalidUniverseDomain () throws IOException {
299
+ Mockito .doThrow (
300
+ new UnauthenticatedException (
301
+ null , GrpcStatusCode .of (Status .Code .UNAUTHENTICATED ), false ))
302
+ .when (endpointContext )
303
+ .validateUniverseDomain (Mockito .any (Credentials .class ), Mockito .any (GrpcStatusCode .class ));
304
+ GrpcCallContext context =
305
+ GrpcCallContext .createDefault ()
306
+ .withChannel (mockChannel )
307
+ .withCredentials (credentials )
308
+ .withEndpointContext (endpointContext );
309
+
310
+ CallOptions callOptions = context .getCallOptions ();
311
+
312
+ MethodDescriptor <Color , Money > descriptor = FakeServiceGrpc .METHOD_RECOGNIZE ;
313
+ UnauthenticatedException exception =
314
+ assertThrows (
315
+ UnauthenticatedException .class , () -> GrpcClientCalls .newCall (descriptor , context ));
316
+ assertThat (exception .getStatusCode ().getCode ()).isEqualTo (GrpcStatusCode .Code .UNAUTHENTICATED );
317
+ Mockito .verify (mockChannel , Mockito .never ()).newCall (descriptor , callOptions );
318
+ }
319
+
320
+ // This test is when the MDS is unable to return a valid universe domain
321
+ @ Test
322
+ public void testUniverseDomainNotReady_shouldRetry () throws IOException {
323
+ Mockito .doThrow (new GoogleAuthException (true ))
324
+ .when (endpointContext )
325
+ .validateUniverseDomain (Mockito .any (Credentials .class ), Mockito .any (GrpcStatusCode .class ));
326
+ GrpcCallContext context =
327
+ GrpcCallContext .createDefault ()
328
+ .withChannel (mockChannel )
329
+ .withCredentials (credentials )
330
+ .withEndpointContext (endpointContext );
331
+
332
+ CallOptions callOptions = context .getCallOptions ();
333
+
334
+ MethodDescriptor <Color , Money > descriptor = FakeServiceGrpc .METHOD_RECOGNIZE ;
335
+ UnavailableException exception =
336
+ assertThrows (
337
+ UnavailableException .class , () -> GrpcClientCalls .newCall (descriptor , context ));
338
+ assertThat (exception .getStatusCode ().getCode ()).isEqualTo (GrpcStatusCode .Code .UNAVAILABLE );
339
+ Truth .assertThat (exception .isRetryable ()).isTrue ();
340
+ Mockito .verify (mockChannel , Mockito .never ()).newCall (descriptor , callOptions );
341
+ }
235
342
}
0 commit comments