test: deterministic regression for the Codex watchdog freezing the command before reaping its children

The existing stubborn-child test caught the reap-then-kill race only some of
the time (2 of 3 runs on the pre-fix watchdog). A pkill that sleeps after
reaping widens the window between reaping the children and killing the
command, so a watchdog that does not SIGSTOP the command first always lets
it print "late" after the deadline. Fails 3 of 3 on the pre-fix watchdog,
passes 3 of 3 on the current one.
This commit is contained in:
garrytan committed 2026-10-06 20:43:44 +00:00
1 parent fa79a3071e
commit f6d2f3376d
1 file changed
+21
+21
View File
@@ -378,6 +378,27 @@ describe('gstack-codex-probe: timeout wrapper + namespace hygiene', () => {
}
});
test('bash-native watchdog freezes the command before reaping its children, so nothing prints after the deadline', () => {
// A slow pkill widens the window between reaping the children and killing
// the command: a watchdog that does not stop the command first lets it run
// on past its killed child and print after the deadline.
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-watchdog-freeze-'));
try {
const which = (tool: string) => spawnSync('bash', ['-c', `command -v ${tool}`], { timeout: 5000 }).stdout.toString().trim();
for (const tool of ['bash', 'sleep', 'cat']) fs.symlinkSync(which(tool), path.join(dir, tool));
fs.writeFileSync(path.join(dir, 'pkill'), `#!${which('bash')}\n"${which('pkill')}" "$@"\nrc=$?\n"${which('sleep')}" 0.5\nexit "$rc"\n`, { mode: 0o755 });
const stubborn = path.join(dir, 'stubborn');
fs.writeFileSync(stubborn, `#!${which('bash')}\ntrap '' TERM\necho partial\nsleep 30\necho late\n`, { mode: 0o755 });
const r = runProbe({
snippet: `_GSTACK_CODEX_KILL_AFTER=1 _gstack_codex_timeout_wrapper 1 "${stubborn}"; echo "rc=$?"`,
env: { PATH: dir },
});
expect(r.stdout).toBe('partial\nrc=124\n');
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});
for (const native of [false, true]) test(`E5: ${native ? 'bash-native watchdog' : 'timeout(1)'} passes the caller's stdin to the command (#1674)`, () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-watchdog-stdin-'));
try {