4343import com .google .api .core .ApiFutures ;
4444import com .google .api .gax .core .FakeApiClock ;
4545import com .google .api .gax .core .RecordingScheduler ;
46+ import com .google .api .gax .httpjson .testing .TestApiTracerFactory ;
4647import com .google .api .gax .retrying .RetrySettings ;
4748import com .google .api .gax .rpc .ApiCallContext ;
4849import com .google .api .gax .rpc .ApiException ;
@@ -80,6 +81,7 @@ class RetryingTest {
8081
8182 private final Integer initialRequest = 1 ;
8283 private final Integer modifiedRequest = 0 ;
84+ private TestApiTracerFactory tracerFactory ;
8385
8486 private final HttpJsonCallSettings <Integer , Integer > httpJsonCallSettings =
8587 HttpJsonCallSettings .<Integer , Integer >newBuilder ()
@@ -115,8 +117,11 @@ class RetryingTest {
115117 void resetClock () {
116118 fakeClock = new FakeApiClock (System .nanoTime ());
117119 executor = RecordingScheduler .create (fakeClock );
120+ tracerFactory = new TestApiTracerFactory ();
118121 clientContext =
119122 ClientContext .newBuilder ()
123+ // we use a custom tracer to confirm whether the retrials are being recorded.
124+ .setTracerFactory (tracerFactory )
120125 .setExecutor (executor )
121126 .setClock (fakeClock )
122127 .setDefaultCallContext (HttpJsonCallContext .createDefault ())
@@ -130,6 +135,7 @@ void teardown() {
130135
131136 @ Test
132137 void retry () {
138+ // set a retriable that will fail 3 times before returning "2"
133139 ImmutableSet <StatusCode .Code > retryable = ImmutableSet .of (Code .UNAVAILABLE );
134140 Mockito .when (callInt .futureCall ((Integer ) any (), (ApiCallContext ) any ()))
135141 .thenReturn (ApiFutures .<Integer >immediateFailedFuture (HTTP_SERVICE_UNAVAILABLE_EXCEPTION ))
@@ -143,6 +149,9 @@ void retry() {
143149 HttpJsonCallableFactory .createUnaryCallable (
144150 callInt , callSettings , httpJsonCallSettings , clientContext );
145151 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 ();
146155
147156 // Capture the argument passed to futureCall
148157 ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
@@ -180,6 +189,9 @@ void retryTotalTimeoutExceeded() {
180189 HttpJsonCallableFactory .createUnaryCallable (
181190 callInt , callSettings , httpJsonCallSettings , clientContext );
182191 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 ();
183195 // Capture the argument passed to futureCall
184196 ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
185197 verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
@@ -200,6 +212,9 @@ void retryMaxAttemptsExceeded() {
200212 HttpJsonCallableFactory .createUnaryCallable (
201213 callInt , callSettings , httpJsonCallSettings , clientContext );
202214 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 ();
203218 // Capture the argument passed to futureCall
204219 ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
205220 verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
@@ -220,6 +235,9 @@ void retryWithinMaxAttempts() {
220235 HttpJsonCallableFactory .createUnaryCallable (
221236 callInt , callSettings , httpJsonCallSettings , clientContext );
222237 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 ();
223241 // Capture the argument passed to futureCall
224242 ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
225243 verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
@@ -246,6 +264,9 @@ void retryOnStatusUnknown() {
246264 HttpJsonCallableFactory .createUnaryCallable (
247265 callInt , callSettings , httpJsonCallSettings , clientContext );
248266 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 ();
249270 // Capture the argument passed to futureCall
250271 ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
251272 verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
@@ -264,6 +285,9 @@ void retryOnUnexpectedException() {
264285 HttpJsonCallableFactory .createUnaryCallable (
265286 callInt , callSettings , httpJsonCallSettings , clientContext );
266287 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 ();
267291 assertThat (exception ).hasCauseThat ().isSameInstanceAs (throwable );
268292 // Capture the argument passed to futureCall
269293 ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
@@ -293,6 +317,9 @@ void retryNoRecover() {
293317 HttpJsonCallableFactory .createUnaryCallable (
294318 callInt , callSettings , httpJsonCallSettings , clientContext );
295319 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 ();
296323 assertThat (exception ).isSameInstanceAs (apiException );
297324 // Capture the argument passed to futureCall
298325 ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
@@ -319,6 +346,10 @@ void retryKeepFailing() {
319346
320347 UncheckedExecutionException exception =
321348 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 ();
322353 assertThat (exception ).hasCauseThat ().isInstanceOf (ApiException .class );
323354 assertThat (exception ).hasCauseThat ().hasMessageThat ().contains ("Unavailable" );
324355 // Capture the argument passed to futureCall
@@ -359,6 +390,9 @@ void testKnownStatusCode() {
359390 callInt , callSettings , httpJsonCallSettings , clientContext );
360391 ApiException exception =
361392 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 ();
362396 assertThat (exception .getStatusCode ().getTransportCode ())
363397 .isEqualTo (HTTP_CODE_PRECONDITION_FAILED );
364398 assertThat (exception ).hasMessageThat ().contains ("precondition failed" );
@@ -383,6 +417,9 @@ void testUnknownStatusCode() {
383417 UnknownException exception =
384418 assertThrows (UnknownException .class , () -> callable .call (initialRequest ));
385419 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 ();
386423 // Capture the argument passed to futureCall
387424 ArgumentCaptor <Integer > argumentCaptor = ArgumentCaptor .forClass (Integer .class );
388425 verify (callInt , atLeastOnce ()).futureCall (argumentCaptor .capture (), any (ApiCallContext .class ));
0 commit comments