Skip to content

fix(test): remove two CI flakes — EPIPE on early-exit stdin, and an over-tight async watchdog [DEV-150, DEV-151]#74

Merged
P4suta merged 2 commits into
mainfrom
feature/dev-150-flaky-run-stdin-epipe
Jul 23, 2026
Merged

fix(test): remove two CI flakes — EPIPE on early-exit stdin, and an over-tight async watchdog [DEV-150, DEV-151]#74
P4suta merged 2 commits into
mainfrom
feature/dev-150-flaky-run-stdin-epipe

Conversation

@P4suta

@P4suta P4suta commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Two independent test-harness flakes that were turning main and PR runs red. Both are test bugs, not product bugs. Linear: DEV-150, DEV-151.

1. EPIPE when a CLI rejects stdin early (DEV-150)

Turned main red on 6d51600 (run 30050968242) — and reproduced on re-run.

zip_profile_rejects_standard_input_as_usage asserts that oxarchive package validate - refuses - as a usage error (exit 2). That behaviour is correct: the CLI exits immediately without reading stdin, closing the pipe. The run_stdin helper raced that exit — write_all(jar).expect("write stdin") returns BrokenPipe (EPIPE) whenever the child exits before the bytes land in the pipe buffer, so .expect panicked based purely on scheduling.

Fix: treat BrokenPipe as an expected outcome of feeding a process that may reject its arguments without consuming input; every other write error still panics. Stdin is scoped closed before wait_with_output, so children that do read stdin (deb_validates_from_standard_input) still see EOF. The test's assertions are unchanged.

2. Async deadlock watchdog too tight for emulated/loaded runners (DEV-151)

Failed big-endian (s390x, qemu) and test (macos-latest) on this PR's first run:

watchdog: `async_xz_never_deadlocks_under_slow_source` did not complete within 30s;
aborting the deadlocked test

Not a deadlock — the watchdog (added with DEV-124) mistook slowness for one. Driving the reader one byte per poll for 50 iterations honestly exceeds 30s on an emulated s390x and a loaded macOS runner, so the guard meant to kill flakes became one.

Fix: detection determinism comes from the park/unpark driver, not the repeat count — the executor has nothing else to poll, so a lost wakeup parks forever on the first iteration. Trim the loop to 8 repeats and raise the budget to 240s via a documented WATCHDOG_BUDGET. A real hang still aborts fast and attributably, well inside the job's timeout-minutes; honest slowness no longer trips it.

Verification

  • package_cli → 9 passed; the previously flaky stdin test repeated 12/12 green.
  • async_stream_v2 → 6 passed, suite now 0.30s natively (was dominated by the 50-iteration loop).

🤖 Generated with Claude Code

`zip_profile_rejects_standard_input_as_usage` intermittently failed (observed on
`main` run 30050968242, passing on the portable profile and failing on the native
one in the same job). The product behaviour is correct: `oxarchive package
validate -` refuses `-` as a usage error and exits 2 *without* reading stdin,
closing the pipe. The `run_stdin` helper then raced that exit — `write_all` of the
JAR body returns `BrokenPipe` (EPIPE) whenever the child exits before the bytes
land in the pipe buffer, and `.expect("write stdin")` turned that into a panic.

Treat `BrokenPipe` as an expected outcome of feeding a process that may reject its
arguments without consuming input; every other write error still panics. Stdin is
scoped so it is closed before `wait_with_output`, so children that *do* read stdin
(e.g. `deb_validates_from_standard_input`) still see EOF.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@P4suta
P4suta enabled auto-merge (squash) July 23, 2026 23:22
…[DEV-151]

`async_xz_never_deadlocks_under_slow_source` (added by DEV-124) aborted on the
`big-endian (s390x, qemu)` and `test (macos-latest)` jobs:

    watchdog: `async_xz_never_deadlocks_under_slow_source` did not complete
    within 30s; aborting the deadlocked test

That was not a deadlock — it was the watchdog mistaking *slowness* for one. Driving
the reader one byte per poll for 50 iterations honestly exceeds 30s on an emulated
s390x (10-50x slower than a native host) and on a loaded macOS runner, so the guard
meant to kill flakes became a flake itself.

Detection determinism comes from the park/unpark driver, not the repeat count: the
executor has nothing else to poll, so a lost wakeup parks forever on the very first
iteration. Trim the loop to 8 repeats (still exercising the NeedInput/Output
interleaving) and raise the budget to 240s via a documented `WATCHDOG_BUDGET`
constant — a real hang still aborts fast and attributably, well inside the job's
`timeout-minutes`, while honest slowness no longer trips it. The suite now runs in
0.30s natively.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@P4suta P4suta changed the title fix(test): tolerate EPIPE when a CLI rejects stdin early [DEV-150] fix(test): remove two CI flakes — EPIPE on early-exit stdin, and an over-tight async watchdog [DEV-150, DEV-151] Jul 23, 2026
@P4suta
P4suta merged commit 2d8f92a into main Jul 23, 2026
22 checks passed
@P4suta
P4suta deleted the feature/dev-150-flaky-run-stdin-epipe branch July 23, 2026 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant