1616
1717package com .google .cloud .firestore ;
1818
19+ import static com .google .api .core .ApiFutures .immediateFailedFuture ;
1920import static com .google .cloud .firestore .LocalFirestoreHelper .IMMEDIATE_RETRY_SETTINGS ;
2021import static com .google .cloud .firestore .LocalFirestoreHelper .SINGLE_FIELD_PROTO ;
2122import static com .google .cloud .firestore .LocalFirestoreHelper .TRANSACTION_ID ;
8889public class TransactionTest {
8990
9091 private final ApiFuture <GeneratedMessageV3 > RETRYABLE_API_EXCEPTION =
91- ApiFutures . immediateFailedFuture (
92+ immediateFailedFuture (
9293 new ApiException (
9394 new Exception ("Test exception" ), GrpcStatusCode .of (Status .Code .UNKNOWN ), true ));
9495
@@ -244,7 +245,7 @@ public void rollbackOnCallbackApiFutureErrorAsync() {
244245
245246 ApiFuture <String > transaction =
246247 firestoreMock .runAsyncTransaction (
247- t -> ApiFutures . immediateFailedFuture (new Exception ("Expected exception" )), options );
248+ t -> immediateFailedFuture (new Exception ("Expected exception" )), options );
248249
249250 try {
250251 transaction .get ();
@@ -262,7 +263,7 @@ public void rollbackOnCallbackApiFutureErrorAsync() {
262263
263264 @ Test
264265 public void noRollbackOnBeginFailure () {
265- doReturn (ApiFutures . immediateFailedFuture (new Exception ("Expected exception" )))
266+ doReturn (immediateFailedFuture (new Exception ("Expected exception" )))
266267 .when (firestoreMock )
267268 .sendRequest (
268269 requestCapture .capture (), ArgumentMatchers .<UnaryCallable <Message , Message >>any ());
@@ -288,7 +289,7 @@ public void noRollbackOnBeginFailure() {
288289
289290 @ Test
290291 public void noRollbackOnBeginFailureAsync () {
291- doReturn (ApiFutures . immediateFailedFuture (new Exception ("Expected exception" )))
292+ doReturn (immediateFailedFuture (new Exception ("Expected exception" )))
292293 .when (firestoreMock )
293294 .sendRequest (
294295 requestCapture .capture (), ArgumentMatchers .<UnaryCallable <Message , Message >>any ());
@@ -493,7 +494,7 @@ public void retriesCommitBasedOnErrorCode() throws Exception {
493494 new ResponseStubber () {
494495 {
495496 put (begin (), beginResponse ("foo1" ));
496- put (commit ("foo1" ), ApiFutures . immediateFailedFuture (e ));
497+ put (commit ("foo1" ), immediateFailedFuture (e ));
497498 put (rollback ("foo1" ), rollbackResponse ());
498499 put (begin ("foo1" ), beginResponse ("foo2" ));
499500 put (commit ("foo2" ), commitResponse (0 , 0 ));
@@ -503,40 +504,41 @@ public void retriesCommitBasedOnErrorCode() throws Exception {
503504 new ResponseStubber () {
504505 {
505506 put (begin (), beginResponse ("foo1" ));
506- put (commit ("foo1" ), ApiFutures . immediateFailedFuture (e ));
507+ put (commit ("foo1" ), immediateFailedFuture (e ));
507508 put (rollback ("foo1" ), rollbackResponse ());
508509 }
509510 });
510511 }
511512
512513 @ Test
513514 public void retriesRollbackBasedOnErrorCode () throws Exception {
514- final ApiException commitException = exception (Status .Code .ABORTED , true );
515-
515+ final ApiException retryable = exception (Status .Code .ABORTED , true );
516+
517+ // Regardless of exception thrown by rollback, we should never retry
518+ // calling rollback. Rollback is best effort, and will sometimes return
519+ // ABORT error (which a transaction will retry) when transaction no longer
520+ // exists on Firestore server side. Attempting to retry will in some cases
521+ // simply exhaust retries with accumulated backoff delay, when a new
522+ // transaction could simply be started (since the old transaction no longer
523+ // exists server side).
516524 verifyRetries (
517525 /* expectedSequenceWithRetry= */ e -> {
518- final ApiFuture <GeneratedMessageV3 > rollbackException =
519- ApiFutures .immediateFailedFuture (e );
520526 return new ResponseStubber () {
521527 {
522528 put (begin (), beginResponse ("foo1" ));
523- put (commit ("foo1" ), ApiFutures .immediateFailedFuture (commitException ));
524- put (rollback ("foo1" ), rollbackException );
525- put (rollback ("foo1" ), rollbackResponse ());
529+ put (commit ("foo1" ), immediateFailedFuture (e ));
530+ put (rollback ("foo1" ), immediateFailedFuture (retryable ));
526531 put (begin ("foo1" ), beginResponse ("foo2" ));
527532 put (commit ("foo2" ), commitResponse (0 , 0 ));
528533 }
529534 };
530535 },
531536 /* expectedSequenceWithoutRetry= */ e -> {
532- final ApiFuture <GeneratedMessageV3 > rollbackException =
533- ApiFutures .immediateFailedFuture (e );
534537 return new ResponseStubber () {
535538 {
536539 put (begin (), beginResponse ("foo1" ));
537- put (commit ("foo1" ), ApiFutures .immediateFailedFuture (commitException ));
538- put (rollback ("foo1" ), rollbackException );
539- put (rollback ("foo1" ), rollbackResponse ());
540+ put (commit ("foo1" ), immediateFailedFuture (e ));
541+ put (rollback ("foo1" ), immediateFailedFuture (retryable ));
540542 }
541543 };
542544 });
0 commit comments