Repository navigation
Recover Flutter Chrome tests stalled on a lost Browser.close reply - #1832
Merged
Merged
Conversation
flutter test --platform chrome awaits Chrome's DevTools Browser.close reply with no timeout and hangs after reporting results when Chrome exits first. Web Chat Contract now runs its Chrome tests under the supervisor, which takes the JSON file reporter's result once the CLI outlives its browser by 30 seconds after the done event, and fails any other stall at a 10-minute deadline. Refs #1702
Ubuntu runners ship uutils coreutils, whose sleep refuses to run under another name.
This was referenced Nov 9, 2026
leehack
marked this pull request as ready for review
November 9, 2026 02:08
Contributor
|
Chat app preview removed for |
This was referenced Nov 9, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
flutter test --platform chromecloses Chrome by sending DevToolsBrowser.closeand awaiting the reply with no timeout (flutter_tools/lib/src/web/chrome.dart:571-572);webkit_inspection_protocolnever fails pending commands when the socket closes. If Chrome exits before the reply arrives, the CLI waits forever after printing results. The Model Store moved todart test -p chromein #1773;Web Chat Contractwas the last CI path still exposed, up to its 40-minute job limit.Web Chat Contractnow runs its Chrome tests undertool/ci/supervise_chrome_test.pywithflutter test --file-reporter json:..., a 10-minute deadline and a diagnostics artifact. New--reporter-file/--post-done-seconds(default 30) supervisor options: when the CLI is still running 30 s after the JSON reporter'sdoneevent and no browser process remains, the supervisor stops the owned processes, logs a::warning::, recordsbrowser_close_stallinresult.json, and exits with package:test's own verdict (0 only forsuccess: truewith at least one visible test; 1 forsuccess: false). Every other stall (browser alive, nodone,success: null, zero tests) still fails at the deadline (124). A real CLI exit always wins over the reporter, and a pre-existing reporter file refuses to start.doneevent, which test_core emits beforerunner.close()closes Chrome. The CLI's own exit code after a forced stop is unusable: Flutter exits 0 on SIGTERM even with a failing test (fault run below).Production-readiness scope
Web Chat Contractjob; the supervisor stays Linux-only (/proc, pidfd).--reporter-file, supervisor behavior is unchanged (Model Store lane).Browser.closewait influtter_tools, or fail pending commands on close inwebkit_inspection_protocol) has no upstream issue yet. The loading-stage stall (run 41709296800, Chrome alive, no results) remains unattributed; on this path it is now bounded at 10 minutes with process diagnostics instead of 40.Completeness checklist
doc/ci_selection.md"Flutter Chrome test shutdown". Changelog N/A: nothing users can observe.ci.yml.result.json/event fields are booleans and counts; no paths, argv or environment recorded.PR type guidance
Test Plan
dart run tool/prepare_workspace.dart: tree clean.dart format --output=none --set-exit-if-changed .: no Dart changes.dart analyze: N/A, no Dart changes.dart test -p vm test/unit/tooling/: 1590 pass, 6 fail (windows_registry_qualification_test.dart, needspwsh; unrelated, same as onmain).dart test -p chrome: N/A, no library or web code change.coverage-lib: N/A, nolib/change.python3 -m unittest discover -s test/ci -p 'test_*.py'passes on macOS (Linux-only cases skipped);test_supervise_chrome_test.py28/28 passes on Linux (Debian trixie arm64 container), 3 consecutive runs.Fault injection: before / after
Debian trixie arm64 container, Chromium 156.0.8078.79, Flutter 3.47.1,
flutter createwidget test,flutter test --platform chrome --file-reporter json:...under the supervisor. ACHROME_EXECUTABLEshim relays the DevTools port (strippingpermessage-deflateso commands are visible);dropdiscards Chrome's bytes afterBrowser.close,passonly relays.maindrop, passing testAll tests passed!, Chrome exit 0, onlydart:flutter_to+dart:frontend_sleft infutex_do_wait: the hosted job 125206388946 signature. Reporter file already held{"success":true,"type":"done"}.drop, passing testbrowser_close_stall30.0 s afterreporter_done; no surviving processdrop, failing testpass, passing testBrowser.closereply seen every run; no stall recovery, no forced cleanupHosted history (ci.yml, 400 runs, 2026-10-30 to 2026-11-08)
Web Chat Contract/Run chat app testsModel StoreChrome step (supervised,dart test)Model StoreAnalyze and test(pre-#1773flutter test)The race is rare (0/331 on Web Chat), so reruns cannot show a frequency change; the fault table is the before/after evidence, and the hosted CI runs confirm the supervised step adds no stall on the normal path.
Hosted supervised step on this head
browser_close_stalldoneto CLI exitMatrix Evidence
examples-testshigh-risk-exact-head-independent-qaec2ffba46/b78008cf36fb2d1fcd(no blocking findings); exact-head re-audit atec2ffba46: conflict resolution keeps only both lines, later merges' patch-ids equal main's #1835/#1825, PR diff patch-id identical to the audited resolution, Linux container 29/29, Dart tooling +44, Web Chat Contract run 42546893494 passed with no recovery triggeredReview Notes
ec2ffba464941de4879bf6159ff806382441e9b0againstmainb78008cf3. The maintainer approved deriving pass/fail from package:test's structureddoneevent; #1702 stays open to remove the recovery once flutter/flutter#196191 is fixed.6fb2d1fcdconflicted withmain5300a6c03(#1828) intool/ci/supervise_chrome_test.py; resolved by a merge commit keepingreserve_standard_descriptors()first, then the stale-reporter check. Merge headec2cf3400d43c84d37be3599f776b24169c3984a(treeaa3fed8ac59a, matching the auditor's resolution). Local on the new head:test_supervise_chrome_test.pypasses (Linux cases skipped on macOS), format clean, analyze clean,chrome_test_supervisor_test.dart+ci_workflow_selection_test.dart44 pass.main9423d6737(#1835) merged so the audit base is an ancestor of the head. New head6617cdd72aecf4fe13b44a21834d1d7213a33221; the diff againstec2cf3400touches onlytool/native/sync_native_release_pins.pyandtool/native/test_sync_native_release_pins.py. Supervisor Python tests pass. CI on this head: 33 pass, 8 skipped, 0 fail.mainb78008cf3(#1825); new headec2ffba464941de4879bf6159ff806382441e9b0, bringing in only Skip delete-pending model cache entries on Windows instead of failing removal #1825's files. CI on this head: 33 pass, 8 skipped, 0 fail.6fb2d1fcd,ec2cf3400and6617cdd72no longer count; current evidence is onec2ffba46.recovered_exitvs leftover-process/EOF to 125) is not pinned by tests; (2) the workflow test does not pin the 30 s--post-done-secondsdefault; (3) a leftover reporter file makes the supervisor exit 125 silently, with no message or diagnostics directory.6fb2d1fcdf42a4fcbbdfa96073a48fdd73a61ef9(33 pass, 8 skipped; CI run 42535897645). The first head failed one new fixture on Ubuntu (uutilssleeprefuses a renamed binary); the fake browser is now a script.High-risk regression review
regressionPolicysurface:.github/workflows/ci.yml)6fb2d1fcd, exact-head re-audit atec2ffba46): PASS, no blocking findingsec2ffba464941de4879bf6159ff806382441e9b0/b78008cf31fbf6c967e1cc5bf2c557764c2072d3(earlier heads6fb2d1fcd,ec2cf3400,6617cdd72)tool/testing/high_risk_readiness.dartexit 2 (unverifiedPrerequisites/externalPrerequisitesUnavailable), repository-local evidence consistentWorkflowTest.test_web_chat_chrome_tests_take_only_their_own_reporter_resultfails against baseci.yml; Linux supervisor mutants: dropping the browser-alive check, passing anydoneevent, or allowing a stale reporter file each fail a fixture. Removing the post-donewait (now - done_at >= post_done) is not reliably killed: it failed only 2 of 6 runs, by a race intest_reporter_result_never_replaces_a_real_cli_exit; no test pins that wait deterministically.