-
Notifications
You must be signed in to change notification settings - Fork 55
[coverage] Fix remaining ~0.1% flakiness #2102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Package publishing
Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation. |
PR Health
Breaking changes
|
Package | Change | Current Version | New Version | Needed Version | Looking good? |
---|---|---|---|---|---|
coverage | Breaking | 1.14.0 | 1.14.1 | 2.0.0 Got "1.14.1" expected >= "2.0.0" (breaking changes) |
This check can be disabled by tagging the PR with skip-breaking-check
.
Changelog Entry ✔️
Package | Changed Files |
---|
Changes to files need to be accounted for in their respective changelogs.
Coverage ✔️
File | Coverage |
---|---|
pkgs/coverage/lib/src/isolate_paused_listener.dart | 💚 98 % ⬆️ 0 % |
This check for test coverage is informational (issues shown here will not fail the PR).
API leaks ⚠️
The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.
Package | Leaked API symbols |
---|---|
coverage | _CoverageInfo |
This check can be disabled by tagging the PR with skip-leaking-check
.
License Headers ✔️
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
Files |
---|
no missing headers |
All source files should start with a license header.
Unrelated files missing license headers
Files |
---|
pkgs/bazel_worker/benchmark/benchmark.dart |
pkgs/bazel_worker/example/client.dart |
pkgs/bazel_worker/example/worker.dart |
pkgs/benchmark_harness/integration_test/perf_benchmark_test.dart |
pkgs/boolean_selector/example/example.dart |
pkgs/clock/lib/clock.dart |
pkgs/clock/lib/src/clock.dart |
pkgs/clock/lib/src/default.dart |
pkgs/clock/lib/src/stopwatch.dart |
pkgs/clock/lib/src/utils.dart |
pkgs/clock/test/clock_test.dart |
pkgs/clock/test/default_test.dart |
pkgs/clock/test/stopwatch_test.dart |
pkgs/clock/test/utils.dart |
pkgs/coverage/lib/src/coverage_options.dart |
pkgs/html/example/main.dart |
pkgs/html/lib/dom.dart |
pkgs/html/lib/dom_parsing.dart |
pkgs/html/lib/html_escape.dart |
pkgs/html/lib/parser.dart |
pkgs/html/lib/src/constants.dart |
pkgs/html/lib/src/encoding_parser.dart |
pkgs/html/lib/src/html_input_stream.dart |
pkgs/html/lib/src/list_proxy.dart |
pkgs/html/lib/src/query_selector.dart |
pkgs/html/lib/src/token.dart |
pkgs/html/lib/src/tokenizer.dart |
pkgs/html/lib/src/treebuilder.dart |
pkgs/html/lib/src/utils.dart |
pkgs/html/test/dom_test.dart |
pkgs/html/test/parser_feature_test.dart |
pkgs/html/test/parser_test.dart |
pkgs/html/test/query_selector_test.dart |
pkgs/html/test/selectors/level1_baseline_test.dart |
pkgs/html/test/selectors/level1_lib.dart |
pkgs/html/test/selectors/selectors.dart |
pkgs/html/test/support.dart |
pkgs/html/test/tokenizer_test.dart |
pkgs/html/test/trie_test.dart |
pkgs/html/tool/generate_trie.dart |
pkgs/pubspec_parse/test/git_uri_test.dart |
pkgs/stack_trace/example/example.dart |
pkgs/watcher/test/custom_watcher_factory_test.dart |
pkgs/yaml_edit/example/example.dart |
Pull Request Test Coverage Report for Build 15264956178Details
💛 - Coveralls |
|
||
// TODO: Not sure how to write this test, since the RPCError is thrown in | ||
// an async handler, and not propagated to this expectation. | ||
// expect(() => endTest(), throwsA(isA<RPCError>())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bkonyi Any suggestions about how to write this test? This expectation doesn't work. The endTest()
future actually completes successfully. The RPCError is printed to the console as an unhandled exception.
00:00 +22 -1: IsolatePausedListener throw when resuming other isolate is not ignored [E]
resume: (-32000) other
test/isolate_paused_listener_test.dart 533:11 main.<fn>.<fn>.<fn>
package:mockito/src/mock.dart 186:47 Mock.noSuchMethod
test/collect_coverage_mock_test.mocks.dart 1642:14 MockVmService.resume
package:coverage/src/isolate_paused_listener.dart 108:26 IsolatePausedListener._onPause
===== asynchronous gap ===========================
package:coverage/src/isolate_paused_listener.dart 177:7 listenToIsolateLifecycleEvents.onPause
===== asynchronous gap ===========================
package:coverage/src/isolate_paused_listener.dart 200:16 listenToIsolateLifecycleEvents.<fn>
===== asynchronous gap ===========================
package:coverage/src/isolate_paused_listener.dart 277:7 IsolateEventBuffer.add
resume: (-32000) other
test/isolate_paused_listener_test.dart 533:11 main.<fn>.<fn>.<fn>
package:mockito/src/mock.dart 186:47 Mock.noSuchMethod
test/collect_coverage_mock_test.mocks.dart 1642:14 MockVmService.resume
package:coverage/src/isolate_paused_listener.dart 108:26 IsolatePausedListener._onPause
===== asynchronous gap ===========================
package:coverage/src/isolate_paused_listener.dart 177:7 listenToIsolateLifecycleEvents.onPause
===== asynchronous gap ===========================
package:coverage/src/isolate_paused_listener.dart 200:16 listenToIsolateLifecycleEvents.<fn>
===== asynchronous gap ===========================
package:coverage/src/isolate_paused_listener.dart 277:7 IsolateEventBuffer.add
Expected: throws <Instance of 'RPCError'>
Actual: <Closure: () => Future<void>>
Which: returned a Future that emitted <null>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried using expectLater
? I don't think expect
will await
the future returned by the closure, just simply registers a listener.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expectLater
doesn't work either. The problem is that the Future
returned by endTest
/waitUntilAllExited
does complete successfully. The exception doesn't propagate through this future. The stack trace terminates at IsolateEventBuffer.add
, which is invoked by VmService.onIsolateEvent.listen
.
I thought you might have had to solve this problem in VmService
's event listener tests. I feel like there's probably some solution involving Zone
s, but I can't figure out how to make it work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you'd need to use a Zone
if you don't have an error handler setup in isolate_paused_listener.dart
. I noticed you don't actually catch anything there, so it makes sense that it's propagating through to the root zone handler.
I guess the question is, what do you expect to happen in this case? Should this exception be unhandled or just ignored?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When running the tool normally, this error should be reported (with the normal stack trace etc), not ignored. Leaving it as an unhandled exception does that. But for this test I want to catch the error and verify it is what I expect. I guess I'll have another go at using a Zone
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The solution was to wrap the test setup in a Zone
, rather than wrapping the test itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When running the tool normally, this error should be reported (with the normal stack trace etc), not ignored.
Why do we want this error reported? Can it not be safely ignored?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This infra is all about managing the lifecycle of isolates and the VM under test, and the sequencing is pretty complex. This error indicates a bug in that sequencing that could lead to missing coverage (ie failing to collect coverage for an isolate group). If we report the error then it gives me a chance to debug it (or for users to file a bug), but if we ignore the error then the failure mode is that occasionally the coverage report will be incomplete. Much harder to notice and debug.
If I get a report of this error and I'm able to repro it, but it's not clear what's going on and there's no way of fixing the error, and it's rare and harmless, then I'll start ignoring this error. That's what happened for the main isolate error case.
|
||
// TODO: Not sure how to write this test, since the RPCError is thrown in | ||
// an async handler, and not propagated to this expectation. | ||
// expect(() => endTest(), throwsA(isA<RPCError>())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried using expectLater
? I don't think expect
will await
the future returned by the closure, just simply registers a listener.
@@ -11,7 +11,7 @@ import 'package:test_process/test_process.dart'; | |||
|
|||
final String testAppPath = p.join('test', 'test_files', 'test_app.dart'); | |||
|
|||
const Duration timeout = Duration(seconds: 30); | |||
const Duration timeout = Duration(seconds: 60); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the timeout increase necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not directly related to this PR, but I've seen a few flakes of the integration tests on GitHub CI due to timing out
Revisions updated by `dart tools/rev_sdk_deps.dart`. ai (https://github.com/dart-lang/ai/compare/6a71aeb..1d9d60c): 1d9d60c 2025-06-05 Jacob MacDonald handle relative paths under roots without trailing slashes (dart-lang/ai#152) ecosystem (https://github.com/dart-lang/ecosystem/compare/8cebaf0..64aac3a): 64aac3a 2025-06-03 Daco Harkes [health] Bump dart_apitool (dart-lang/ecosystem#360) i18n (https://github.com/dart-lang/i18n/compare/e44af54..43214dd): 43214dde 2025-06-04 Moritz Upgrade to new native_assets (dart-lang/i18n#964) protobuf (https://github.com/dart-lang/protobuf/compare/c69077d..32d53da): 32d53da 2025-06-05 Devon Carew Refactor the test goldens so they have standard file name extensions (google/protobuf.dart#1014) test (https://github.com/dart-lang/test/compare/e2ddae9..0793a2b): 0793a2b3 2025-06-05 Agam Agarwal Add isSorted and related matchers (dart-lang/test#2490) tools (https://github.com/dart-lang/tools/compare/04c6849..e84cbd9): e84cbd9e 2025-06-04 Christophe Coevoet [source_span] Add a test covering the highlighting of non-contiguous spans (dart-lang/tools#1666) 700a3c4d 2025-06-04 Liam Appelbe [coverage] Fix remaining ~0.1% flakiness (dart-lang/tools#2102) webdev (https://github.com/dart-lang/webdev/compare/64492b2..55941b0): 55941b0c 2025-06-05 Kevin Moore [dwds] DRY up MD5/etag logic (dart-lang/webdev#2625) ab7c4d68 2025-06-05 dependabot[bot] Bump the github-actions group across 1 directory with 3 updates (dart-lang/webdev#2593) f149e43f 2025-06-05 Nate Biggs Update e2e_test expectation to look for more consistent message. (dart-lang/webdev#2630) 80b1686b 2025-06-03 Nicholas Shahan Fix e2e_test to work with current DDC output (dart-lang/webdev#2626) Change-Id: I4802d7c4a7e39ba238f2f4ce0748dfa6dba9d8c4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/433240 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Devon Carew <[email protected]>
dart-lang/test#2494 has landed and has almost eliminated all the flakiness from coverage collection. But I'm still seeing about ~0.1% flakiness.
This last bit of flakiness is hard to debug. The error is the same as before (trying to resume the main isolate after the VM service has already shut down), but the event sequence that leads to that point looks correct. There's no reason the service should have shut down at that point.
There's always the option of catching the RPC error and ignoring it. I was hesitant to do this earlier because I didn't want to hide legitimate errors that could lead to missing coverage. But the main isolate's coverage is being collected successfully, so I think it's safe enough to ignore the error at this point.
With this fix in place, I've run 100k tests without any flakes.