Skip to content

Commit 700a3c4

Browse files
authored
[coverage] Fix remaining ~0.1% flakiness (#2102)
1 parent 04c6849 commit 700a3c4

File tree

5 files changed

+89
-31
lines changed

5 files changed

+89
-31
lines changed

pkgs/coverage/CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
## 1.14.1-wip
1+
## 1.14.1
22

33
- Remove dependency on `package:pubspec_parse`.
4+
- Silence a rare error that can occur when trying to resume the main isolate
5+
because the VM service has already shut down. This was responsible for a ~0.1%
6+
flakiness, and is safe to ignore.
47

58
## 1.14.0
69

pkgs/coverage/lib/src/isolate_paused_listener.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ class IsolatePausedListener {
6363

6464
// Resume the main isolate.
6565
if (_mainIsolate != null) {
66-
await _service.resume(_mainIsolate!.id!);
66+
try {
67+
await _service.resume(_mainIsolate!.id!);
68+
} on RPCError {
69+
// The VM Service has already shut down, so there's nothing left to do.
70+
}
6771
}
6872
}
6973

pkgs/coverage/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: coverage
2-
version: 1.14.1-wip
2+
version: 1.14.1
33
description: Coverage data manipulation and formatting
44
repository: https://github.com/dart-lang/tools/tree/main/pkgs/coverage
55
issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Acoverage

pkgs/coverage/test/isolate_paused_listener_test.dart

Lines changed: 78 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -483,10 +483,12 @@ void main() {
483483
late MockVmService service;
484484
late StreamController<Event> allEvents;
485485
late Future<void> allIsolatesExited;
486+
Object? lastError;
486487

487488
late List<String> received;
488489
Future<void> Function(String)? delayTheOnPauseCallback;
489490
late bool stopped;
491+
late Set<String> resumeFailures;
490492

491493
void startEvent(String id, String groupId, [String? name]) =>
492494
allEvents.add(event(
@@ -516,34 +518,48 @@ void main() {
516518
}
517519

518520
setUp(() {
519-
(service, allEvents) = createServiceAndEventStreams();
520-
521-
// Backfill was tested above, so this test does everything using events,
522-
// for simplicity. No need to report any isolates.
523-
when(service.getVM()).thenAnswer((_) async => VM());
524-
525-
received = <String>[];
526-
delayTheOnPauseCallback = null;
527-
when(service.resume(any)).thenAnswer((invocation) async {
528-
final id = invocation.positionalArguments[0];
529-
received.add('Resume $id');
530-
return Success();
531-
});
532-
533-
stopped = false;
534-
allIsolatesExited = IsolatePausedListener(
535-
service,
536-
(iso, isLastIsolateInGroup) async {
537-
expect(stopped, isFalse);
538-
received.add('Pause ${iso.id}. Collect group ${iso.isolateGroupId}? '
539-
'${isLastIsolateInGroup ? 'Yes' : 'No'}');
540-
if (delayTheOnPauseCallback != null) {
541-
await delayTheOnPauseCallback!(iso.id!);
542-
received.add('Pause done ${iso.id}');
521+
Zone.current.fork(
522+
specification: ZoneSpecification(
523+
handleUncaughtError: (Zone self, ZoneDelegate parent, Zone zone,
524+
Object error, StackTrace stackTrace) {
525+
lastError = error;
526+
},
527+
),
528+
).runGuarded(() {
529+
(service, allEvents) = createServiceAndEventStreams();
530+
531+
// Backfill was tested above, so this test does everything using events,
532+
// for simplicity. No need to report any isolates.
533+
when(service.getVM()).thenAnswer((_) async => VM());
534+
535+
received = <String>[];
536+
delayTheOnPauseCallback = null;
537+
resumeFailures = <String>{};
538+
when(service.resume(any)).thenAnswer((invocation) async {
539+
final id = invocation.positionalArguments[0];
540+
received.add('Resume $id');
541+
if (resumeFailures.contains(id)) {
542+
throw RPCError('resume', -32000, id);
543543
}
544-
},
545-
(message) => received.add(message),
546-
).waitUntilAllExited();
544+
return Success();
545+
});
546+
547+
stopped = false;
548+
allIsolatesExited = IsolatePausedListener(
549+
service,
550+
(iso, isLastIsolateInGroup) async {
551+
expect(stopped, isFalse);
552+
received
553+
.add('Pause ${iso.id}. Collect group ${iso.isolateGroupId}? '
554+
'${isLastIsolateInGroup ? 'Yes' : 'No'}');
555+
if (delayTheOnPauseCallback != null) {
556+
await delayTheOnPauseCallback!(iso.id!);
557+
received.add('Pause done ${iso.id}');
558+
}
559+
},
560+
(message) => received.add(message),
561+
).waitUntilAllExited();
562+
});
547563
});
548564

549565
test('ordinary flows', () async {
@@ -889,5 +905,40 @@ void main() {
889905
// Don't try to resume B, because the VM service is already shut down.
890906
]);
891907
});
908+
909+
test('throw when resuming main isolate is ignored', () async {
910+
resumeFailures = {'main'};
911+
912+
startEvent('main', '1');
913+
startEvent('other', '2');
914+
pauseEvent('other', '2');
915+
exitEvent('other', '2');
916+
pauseEvent('main', '1');
917+
exitEvent('main', '1');
918+
919+
await endTest();
920+
expect(lastError, isNull);
921+
922+
expect(received, [
923+
'Pause other. Collect group 2? Yes',
924+
'Resume other',
925+
'Pause main. Collect group 1? Yes',
926+
'Resume main',
927+
]);
928+
});
929+
930+
test('throw when resuming other isolate is not ignored', () async {
931+
resumeFailures = {'other'};
932+
933+
startEvent('main', '1');
934+
startEvent('other', '2');
935+
pauseEvent('other', '2');
936+
exitEvent('other', '2');
937+
pauseEvent('main', '1');
938+
exitEvent('main', '1');
939+
940+
await endTest();
941+
expect(lastError, isA<RPCError>());
942+
});
892943
});
893944
}

pkgs/coverage/test/test_util.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import 'package:test_process/test_process.dart';
1111

1212
final String testAppPath = p.join('test', 'test_files', 'test_app.dart');
1313

14-
const Duration timeout = Duration(seconds: 30);
14+
const Duration timeout = Duration(seconds: 60);
1515

1616
Future<TestProcess> runTestApp() => TestProcess.start(
1717
Platform.resolvedExecutable,

0 commit comments

Comments
 (0)