Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,8 @@ public void transactionGet(
DocumentSnapshot.ServerTimestampBehavior.NONE));
} catch (Exception e) {
ExceptionConverter.sendErrorToFlutter(result, e);
} catch (Throwable t) {
ExceptionConverter.sendErrorToFlutter(result, new Exception(t));
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,15 @@ public void onListen(Object arguments, EventSink events) {

try {
if (!semaphore.tryAcquire(timeout, TimeUnit.MILLISECONDS)) {
return FlutterFirebaseFirestoreTransactionResult.failed(
// Throw a non-FirebaseFirestoreException so the Android SDK
// does not retry or commit. Returning a failed result object
// makes apply() succeed, which commits and then crashes a later
// transaction.get (see #18666).
throw new RuntimeException(
new FirebaseFirestoreException("timed out", Code.DEADLINE_EXCEEDED));
}
} catch (InterruptedException e) {
return FlutterFirebaseFirestoreTransactionResult.failed(
throw new RuntimeException(
new FirebaseFirestoreException("interrupted", Code.DEADLINE_EXCEEDED));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,34 @@ void runTransactionTests() {
skip: kIsWeb || defaultTargetPlatform == TargetPlatform.windows,
);

test(
'should not crash when a get is issued after the transaction timeout',
() async {
final DocumentReference<Map<String, dynamic>> first =
await initializeTest('timeout-second-get-1');
final DocumentReference<Map<String, dynamic>> second =
await initializeTest('timeout-second-get-2');
await first.set(<String, Object>{'v': 1});
await second.set(<String, Object>{'v': 2});

await expectLater(
firestore.runTransaction(
(Transaction transaction) async {
await transaction.get(first);
await Future<void>.delayed(const Duration(seconds: 2));
await transaction.get(second);
},
timeout: const Duration(seconds: 1),
),
throwsA(
isA<FirebaseException>()
.having((e) => e.code, 'code', 'deadline-exceeded'),
),
);
},
skip: kIsWeb || defaultTargetPlatform != TargetPlatform.android,
);

test('should throw with exception', () async {
try {
await firestore.runTransaction((Transaction transaction) async {
Expand Down
Loading