test: remove three fixture races from intermittently failing app-host tests

Merged
AU
17d ago
+106-29

Three app-host tests that failed intermittently in main's full suite (#15488) raced their own fixtures, not the product. Each now waits for the condition it depends on instead of a fixed delay or ordering the scheduler doesn't guarantee. Each assertion checks the same thing as before.

  • SSHStartupManualReconnectTests/directSignalInterruptsPersistentAttachAuthenticationBackoff() (run 36645415013, Cocoa error 260).
    • The fake sleep wrote its ready marker before its PID file. The test waits for ready, then reads the PID file.
    • A fixture descheduled between the two writes left no PID file.
    • The fixture now writes the PID first. The file stays at 913 lines.
  • BrowserOmnibarPerformanceSupportTests/testSuggestionRefreshSchedulerInvalidatesQueuedRefreshOnCancel (run 36623504600, 1 s timeout with nil).
    • After the debounce clock advances, the refresh task has to hop from the clock actor back to the main actor before it checks its generation and emits.
    • Two Task.yield() calls cannot order that hop before cancelPendingRefresh(). When the cancel won, nothing was emitted.
    • The listener now waits for the emission itself, then cancels and asserts that the emitted generation is rejected.
  • TerminalPlainTextPasteStartupTests/clipboardRestorationAfterNativePaste() (run 36645415013, trial 0 received no bytes after the 20 s receipt wait).
    • A 600 ms sleep stood in for "the prewarmed plain-text reader has started". A slow launch through the fixture's wrapper on a loaded runner outlasted it, so trial 0 missed the sender's 100 ms clipboard restore.
    • The fixture now waits until the reader was prewarmed at init and has served one read.
    • The final launches == ["text"] assertion still holds, because the readiness read reuses the same reader.

Evidence

The proofs use app-host-test-rerun.yml with the app build from full-suite run 36685498203 (478e3232b):

  • SSH, deterministic red/green. Both runs add a 1 s delay between the fixture's two writes, for the proof only; it isn't committed.
    • Original order: run 36710919348 failed 3 of 3 with the CI error, Cocoa error 260: The file "backoff-pid" couldn't be opened because there is no such file.
    • Fixed order: run 36710923192 passed 3 of 3. That job's red status comes from an artifact upload timeout after the tests (Failed to CreateArtifact: ETIMEDOUT).
  • All three fixes, 20 iterations each: run 36713674088 passed 20 of 20 for each test: the omnibar XCTest ran 20 iterations, and the SSH and paste tests ran 20 each in Swift Testing.

SSH startup suite: first exec in a fresh app host

This PR's admission lane runs SSHStartupManualReconnectTests first in a fresh app host. Its first test, failedVMStartupClosesAfterDismissalWithoutImplicitReconnect, failed there twice: the dismissal prompt never appeared within the 3 s wait, and then the cleanup timed out.

  • What the fleet logs show. The unified logs of both minis (log show) have the cause. syspolicyd held the first new executable the app host ran, the rewritten VM launcher script, before assessing it: 6.3 s on cmuxs-mac-mini-3 and 13.5 s on cmux10s. The kernel then logged ASP: Sleep interrupted and Security policy would not allow process for the launcher, still waiting in exec when the cleanup signalled it.
  • Why only the first test. The app host's later new files were assessed in 0.1โ€“0.3 s. Main's shards pass because earlier suites absorb that one-time stall.
  • Fix. Every shell fixture now exits at once when CMUX_TEST_PRIME_EXEC is set, and is run that way as soon as it is written, like the Claude, Hermes and Pi wrapper fixtures. The rewritten launcher gets the same guard ahead of its self-delete, and the terminal-teardown test primes its copy of it. No wait, budget or assertion changes. writeShellFile moves to the fixtures file, so the suite file stays within its 913-line budget; it is now 908 lines.
  • Evidence. Run 36722931614 ran the whole suite first in a fresh app host on cmuxs-mac-mini-3, the Mac of the second failure, 5 iterations, plus the omnibar test.
    • Everything passed: 65 of 65 Swift Testing runs and 5 of 5 omnibar iterations.
    • The first iteration of failedVMStartupClosesAfterDismissalWithoutImplicitReconnect took 6.58 s and later ones 0.76โ€“0.78 s. The stall still happens, but in the untimed priming step instead of the 3 s wait.

The omnibar test also now asserts that the emitted refresh is accepted before the cancel, so a gate that rejects every refresh no longer passes it.

Changelog

  • none

๐Ÿค– Generated with Claude Code