f3f916f1
test: the pty grace test fails when the child died inside the grace
a73x 2026-09-04 10:16
Commit message
src/server/pty.zig
| Old | New | ||
|---|---|---|---|
| @@ -233,8 +233,25 @@ test "Pty: deinit is bounded even when the child ignores HUP and TERM" { | |||
| 233 | pty.deinit(); | 233 | pty.deinit(); |
| 234 | const elapsed_ms = t.read() / std.time.ns_per_ms; | 234 | const elapsed_ms = t.read() / std.time.ns_per_ms; |
| 235 | 235 | ||
| 236 | // Returned at all is the headline. The bound is the assertion that can | 236 | // The LOWER bound is the property. A child that died to the TERM sent |
| 237 | // still fail fast if someone widens the grace period without meaning to. | 237 | // before its `trap` line ran is dead too, and every assertion here holds |
| 238 | // for it while the SIGKILL path this test is named for was never walked — | ||
| 239 | // a vacuous pass whose only symptom is the suite running faster. The | ||
| 240 | // 300 ms above is 15x the worst arming measured (21 ms, bash 3.2 on a | ||
| 241 | // loaded Mac), so losing that race means the box is slow, not that the | ||
| 242 | // product changed; this turns it into a sentence rather than a green run. | ||
| 243 | // `pty` cannot reach the harness's armed-marker door — that is the | ||
| 244 | // daemon's fixture and this file is under it — so the clock is the pin. | ||
| 245 | if (elapsed_ms < Pty.term_grace_ms) { | ||
| 246 | std.debug.print( | ||
| 247 | "the child died {d} ms into the {d} ms grace: it did not ignore the TERM, " ++ | ||
| 248 | "so the SIGKILL that bounds deinit was never reached\n", | ||
| 249 | .{ elapsed_ms, Pty.term_grace_ms }, | ||
| 250 | ); | ||
| 251 | return error.ChildDiedInsideTheGrace; | ||
| 252 | } | ||
| 253 | // Returned at all is the headline. The upper bound is the assertion that | ||
| 254 | // can still fail fast if someone widens the grace period without meaning to. | ||
| 238 | try std.testing.expect(elapsed_ms < 3000); | 255 | try std.testing.expect(elapsed_ms < 3000); |
| 239 | // Reaped, not merely abandoned: a deinit that returned while leaving a | 256 | // Reaped, not merely abandoned: a deinit that returned while leaving a |
| 240 | // zombie would satisfy the clock and leak the process. | 257 | // zombie would satisfy the clock and leak the process. |