@@ -375,7 +375,7 @@ public void testUpdateTransactionally() {
375
375
ArrayList <Task <Void >> readTasks = new ArrayList <>();
376
376
// A barrier to make sure every transaction reaches the same spot.
377
377
TaskCompletionSource <Void > barrier = new TaskCompletionSource <>();
378
- AtomicInteger started = new AtomicInteger (0 );
378
+ AtomicInteger counter = new AtomicInteger (0 );
379
379
380
380
FirebaseFirestore firestore = testFirestore ();
381
381
DocumentReference doc = firestore .collection ("counters" ).document ();
@@ -388,9 +388,9 @@ public void testUpdateTransactionally() {
388
388
transactionTasks .add (
389
389
firestore .runTransaction (
390
390
transaction -> {
391
+ counter .incrementAndGet ();
391
392
DocumentSnapshot snapshot = transaction .get (doc );
392
393
assertNotNull (snapshot );
393
- started .incrementAndGet ();
394
394
resolveRead .trySetResult (null );
395
395
waitFor (barrier .getTask ());
396
396
transaction .update (doc , map ("count" , snapshot .getDouble ("count" ) + 1.0 ));
@@ -400,10 +400,12 @@ public void testUpdateTransactionally() {
400
400
401
401
// Let all of the transactions fetch the old value and stop once.
402
402
waitFor (Tasks .whenAll (readTasks ));
403
- assertEquals ( 3 , started . intValue ());
404
- // Let all of the transactions continue and wait for them to finish.
403
+ // There should be 3 initial transaction runs.
404
+ assertEquals ( 3 , counter . get ());
405
405
barrier .setResult (null );
406
406
waitFor (Tasks .whenAll (transactionTasks ));
407
+ // There should be a maximum of 3 retries: once for the 2nd update, and twice for the 3rd update
408
+ assertTrue (counter .get () <= 6 );
407
409
// Now all transaction should be completed, so check the result.
408
410
DocumentSnapshot snapshot = waitFor (doc .get ());
409
411
assertEquals (8 , snapshot .getDouble ("count" ).intValue ());
@@ -546,15 +548,17 @@ public void testReadingADocTwiceWithDifferentVersions() {
546
548
FirebaseFirestore firestore = testFirestore ();
547
549
DocumentReference doc = firestore .collection ("counters" ).document ();
548
550
waitFor (doc .set (map ("count" , 15.0 )));
551
+ AtomicInteger counter = new AtomicInteger (0 );
549
552
Exception e =
550
553
waitForException (
551
554
firestore .runTransaction (
552
555
transaction -> {
556
+ counter .incrementAndGet ();
553
557
// Get the doc once.
554
558
DocumentSnapshot snapshot1 = transaction .get (doc );
555
- assertEquals ( 15 , snapshot1 . getDouble ( "count" ). intValue ());
556
- // Do a write outside of the transaction .
557
- waitFor (doc .set (map ("count" , 1234.0 )));
559
+ // Do a write outside of the transaction. Because the transaction will retry, set
560
+ // the document to a different value each time .
561
+ waitFor (doc .set (map ("count" , 1234.0 + counter . get () )));
558
562
// Get the doc again in the transaction with the new version.
559
563
DocumentSnapshot snapshot2 = transaction .get (doc );
560
564
// The get itself will fail, because we already read an earlier version of this
@@ -563,8 +567,6 @@ public void testReadingADocTwiceWithDifferentVersions() {
563
567
return null ;
564
568
}));
565
569
assertEquals (Code .ABORTED , ((FirebaseFirestoreException ) e ).getCode ());
566
- DocumentSnapshot snapshot = waitFor (doc .get ());
567
- assertEquals (1234 , snapshot .getDouble ("count" ).intValue ());
568
570
}
569
571
570
572
@ Test
@@ -622,6 +624,28 @@ public void testCannotHaveAGetWithoutMutations() {
622
624
assertEquals ("Every document read in a transaction must also be written." , e .getMessage ());
623
625
}
624
626
627
+ @ Test
628
+ public void testDoesNotRetryOnPermanentError () {
629
+ final FirebaseFirestore firestore = testFirestore ();
630
+ AtomicInteger count = new AtomicInteger (0 );
631
+ // Make a transaction that should fail with a permanent error
632
+ Task <Void > transactionTask =
633
+ firestore .runTransaction (
634
+ transaction -> {
635
+ count .incrementAndGet ();
636
+ // Get and update a document that doesn't exist so that the transaction fails
637
+ DocumentSnapshot doc =
638
+ transaction .get (firestore .collection ("nonexistent" ).document ());
639
+ transaction .update (doc .getReference (), "foo" , "bar" );
640
+ return null ;
641
+ });
642
+
643
+ // Let all of the transactions fetch the old value and stop once.
644
+ Exception e = waitForException (transactionTask );
645
+ assertEquals (Code .INVALID_ARGUMENT , ((FirebaseFirestoreException ) e ).getCode ());
646
+ assertEquals (1 , count .get ());
647
+ }
648
+
625
649
@ Test
626
650
public void testSuccessWithNoTransactionOperations () {
627
651
FirebaseFirestore firestore = testFirestore ();
0 commit comments