fix: spawn-test stderr persistence and drain-cap deadlock (PR #11 review)
Two bugs caught in supervisor review: 1. Stderr was silently dropped when the Details panel was closed during a crash. _on_spawn_done appended to diag_text only when the panel was already open, and refresh_dependency() clobbered that text on the next field change anyway. Fix: stash the result in self._last_spawn; _full_diag_text() appends the stderr section whenever diag text is generated; _on_spawn_done auto-opens the panel on non-ok outcomes (same pattern as the existing auto_open for missing commands). 2. _drain stopped reading once _STDERR_CAP (4 KB) was reached. A process that writes more than 4 KB then blocked on a full pipe buffer, never exited, and was misclassified as "ok" instead of "crashed". Fix: drain to EOF unconditionally; keep only the first _STDERR_CAP bytes. Regression test: 64 KB stderr + exit(3) → outcome "crashed". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -303,3 +303,18 @@ def test_spawn_test_stdin_not_closed():
|
||||
timeout=0.3,
|
||||
)
|
||||
assert r["outcome"] == "ok", f"expected ok (blocking on stdin), got {r['outcome']}"
|
||||
|
||||
|
||||
def test_spawn_test_large_stderr_does_not_deadlock():
|
||||
# A process that writes >4 KB (pipe buffer territory) to stderr then exits non-zero.
|
||||
# Without EOF-draining, the subprocess blocks on a full pipe and is wrongly
|
||||
# classified as "ok" (still running) instead of "crashed".
|
||||
script = "import sys; sys.stderr.write('x' * 65536); sys.stderr.flush(); sys.exit(3)"
|
||||
r = c.spawn_test(
|
||||
{"command": sys.executable, "args": ["-c", script]},
|
||||
timeout=2.0,
|
||||
)
|
||||
assert r["outcome"] == "crashed", f"expected crashed, got {r['outcome']}"
|
||||
assert r["returncode"] == 3
|
||||
# stderr is capped, not the full 64 KB
|
||||
assert len(r["stderr"]) <= c._STDERR_CAP
|
||||
|
||||
Reference in New Issue
Block a user