43
43
import com .google .api .core .ApiFutures ;
44
44
import com .google .api .gax .core .FakeApiClock ;
45
45
import com .google .api .gax .core .RecordingScheduler ;
46
+ import com .google .api .gax .httpjson .testing .TestApiTracerFactory ;
46
47
import com .google .api .gax .retrying .RetrySettings ;
47
48
import com .google .api .gax .rpc .ApiCallContext ;
48
49
import com .google .api .gax .rpc .ApiException ;
@@ -80,6 +81,7 @@ class RetryingTest {
80
81
81
82
private final Integer initialRequest = 1 ;
82
83
private final Integer modifiedRequest = 0 ;
84
+ private TestApiTracerFactory tracerFactory ;
83
85
84
86
private final HttpJsonCallSettings <Integer , Integer > httpJsonCallSettings =
85
87
HttpJsonCallSettings .<Integer , Integer >newBuilder ()
@@ -115,8 +117,11 @@ class RetryingTest {
115
117
void resetClock () {
116
118
fakeClock = new FakeApiClock (System .nanoTime ());
117
119
executor = RecordingScheduler .create (fakeClock );
120
+ tracerFactory = new TestApiTracerFactory ();
118
121
clientContext =
119
122
ClientContext .newBuilder ()
123
+ // we use a custom tracer to confirm whether the retrials are being recorded.
124
+ .setTracerFactory (tracerFactory )
120
125
.setExecutor (executor )
121
126
.setClock (fakeClock )
122
127
.setDefaultCallContext (HttpJsonCallContext .createDefault ())
@@ -130,6 +135,7 @@ void teardown() {
130
135
131
136
@ Test
132
137
void retry () {
138
+ // set a retriable that will fail 3 times before returning "2"
133
139
ImmutableSet <StatusCode .Code > retryable = ImmutableSet .of (Code .UNAVAILABLE );
134
140
Mockito .when (callInt .futureCall ((Integer ) any (), (ApiCallContext ) any ()))
135
141
.thenReturn (ApiFutures .<Integer >immediateFailedFuture (HTTP_SERVICE_UNAVAILABLE_EXCEPTION ))
@@ -143,6 +149,9 @@ void retry() {
143
149
HttpJsonCallableFactory .createUnaryCallable (
144
150
callInt , callSettings , httpJsonCallSettings , clientContext );
145
151
assertThat (callable .call (initialRequest )).isEqualTo (2 );
152
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isEqualTo (3 );
153
+ assertThat (tracerFactory .getInstance ().getAttemptsStarted ().get ()).isEqualTo (4 );
154
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isFalse ();
146
155
147
156
// Capture the argument passed to futureCall
148
157
ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
@@ -180,6 +189,9 @@ void retryTotalTimeoutExceeded() {
180
189
HttpJsonCallableFactory .createUnaryCallable (
181
190
callInt , callSettings , httpJsonCallSettings , clientContext );
182
191
assertThrows (ApiException .class , () -> callable .call (initialRequest ));
192
+ assertThat (tracerFactory .getInstance ().getAttemptsStarted ().get ()).isEqualTo (1 );
193
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isEqualTo (0 );
194
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isFalse ();
183
195
// Capture the argument passed to futureCall
184
196
ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
185
197
verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
@@ -200,6 +212,9 @@ void retryMaxAttemptsExceeded() {
200
212
HttpJsonCallableFactory .createUnaryCallable (
201
213
callInt , callSettings , httpJsonCallSettings , clientContext );
202
214
assertThrows (ApiException .class , () -> callable .call (initialRequest ));
215
+ assertThat (tracerFactory .getInstance ().getAttemptsStarted ().get ()).isEqualTo (2 );
216
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isEqualTo (2 );
217
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isTrue ();
203
218
// Capture the argument passed to futureCall
204
219
ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
205
220
verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
@@ -220,6 +235,9 @@ void retryWithinMaxAttempts() {
220
235
HttpJsonCallableFactory .createUnaryCallable (
221
236
callInt , callSettings , httpJsonCallSettings , clientContext );
222
237
assertThat (callable .call (initialRequest )).isEqualTo (2 );
238
+ assertThat (tracerFactory .getInstance ().getAttemptsStarted ().get ()).isEqualTo (3 );
239
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isEqualTo (2 );
240
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isFalse ();
223
241
// Capture the argument passed to futureCall
224
242
ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
225
243
verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
@@ -246,6 +264,9 @@ void retryOnStatusUnknown() {
246
264
HttpJsonCallableFactory .createUnaryCallable (
247
265
callInt , callSettings , httpJsonCallSettings , clientContext );
248
266
assertThat (callable .call (initialRequest )).isEqualTo (2 );
267
+ assertThat (tracerFactory .getInstance ().getAttemptsStarted ().get ()).isEqualTo (4 );
268
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isEqualTo (3 );
269
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isFalse ();
249
270
// Capture the argument passed to futureCall
250
271
ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
251
272
verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
@@ -264,6 +285,9 @@ void retryOnUnexpectedException() {
264
285
HttpJsonCallableFactory .createUnaryCallable (
265
286
callInt , callSettings , httpJsonCallSettings , clientContext );
266
287
ApiException exception = assertThrows (ApiException .class , () -> callable .call (initialRequest ));
288
+ assertThat (tracerFactory .getInstance ().getAttemptsStarted ().get ()).isEqualTo (1 );
289
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isEqualTo (0 );
290
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isFalse ();
267
291
assertThat (exception ).hasCauseThat ().isSameInstanceAs (throwable );
268
292
// Capture the argument passed to futureCall
269
293
ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
@@ -293,6 +317,9 @@ void retryNoRecover() {
293
317
HttpJsonCallableFactory .createUnaryCallable (
294
318
callInt , callSettings , httpJsonCallSettings , clientContext );
295
319
ApiException exception = assertThrows (ApiException .class , () -> callable .call (initialRequest ));
320
+ assertThat (tracerFactory .getInstance ().getAttemptsStarted ().get ()).isEqualTo (1 );
321
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isEqualTo (0 );
322
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isFalse ();
296
323
assertThat (exception ).isSameInstanceAs (apiException );
297
324
// Capture the argument passed to futureCall
298
325
ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
@@ -319,6 +346,10 @@ void retryKeepFailing() {
319
346
320
347
UncheckedExecutionException exception =
321
348
assertThrows (UncheckedExecutionException .class , () -> Futures .getUnchecked (future ));
349
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isGreaterThan (0 );
350
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ())
351
+ .isEqualTo (tracerFactory .getInstance ().getAttemptsStarted ().get ());
352
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isTrue ();
322
353
assertThat (exception ).hasCauseThat ().isInstanceOf (ApiException .class );
323
354
assertThat (exception ).hasCauseThat ().hasMessageThat ().contains ("Unavailable" );
324
355
// Capture the argument passed to futureCall
@@ -359,6 +390,9 @@ void testKnownStatusCode() {
359
390
callInt , callSettings , httpJsonCallSettings , clientContext );
360
391
ApiException exception =
361
392
assertThrows (FailedPreconditionException .class , () -> callable .call (initialRequest ));
393
+ assertThat (tracerFactory .getInstance ().getAttemptsStarted ().get ()).isEqualTo (1 );
394
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isEqualTo (0 );
395
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isFalse ();
362
396
assertThat (exception .getStatusCode ().getTransportCode ())
363
397
.isEqualTo (HTTP_CODE_PRECONDITION_FAILED );
364
398
assertThat (exception ).hasMessageThat ().contains ("precondition failed" );
@@ -383,6 +417,9 @@ void testUnknownStatusCode() {
383
417
UnknownException exception =
384
418
assertThrows (UnknownException .class , () -> callable .call (initialRequest ));
385
419
assertThat (exception ).hasMessageThat ().isEqualTo ("java.lang.RuntimeException: unknown" );
420
+ assertThat (tracerFactory .getInstance ().getAttemptsStarted ().get ()).isEqualTo (1 );
421
+ assertThat (tracerFactory .getInstance ().getAttemptsFailed ().get ()).isEqualTo (0 );
422
+ assertThat (tracerFactory .getInstance ().getRetriesExhausted ().get ()).isFalse ();
386
423
// Capture the argument passed to futureCall
387
424
ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
388
425
verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
0 commit comments