import { test } from 'node:test'; import assert from 'node:assert/strict'; import { spawn } from 'node:child_process'; import { once } from 'node:events'; import { mkdtempSync, readFileSync, writeFileSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { fixtureGuard } from './case-sudo-fixture.mjs'; test('fixture cleanup guard starts its budget at the probe marker', async t => { const dir = mkdtempSync(join(tmpdir(), 'guard-')); t.after(() => rmSync(dir, { recursive: true, force: true })); const records = join(dir, 'pids'), startFile = join(dir, 'probe'); writeFileSync(startFile, ''); const child = spawn(process.execPath, ['-e', 'setInterval(()=>{},1000)'], { stdio: 'ignore' }); const exited = once(child, 'exit'); t.after(() => { if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL'); }); const raw = readFileSync(`/proc/${child.pid}/stat`, 'utf8'); const sid = Number(raw.slice(raw.lastIndexOf(') ') + 2).split(' ')[3]); writeFileSync(records, `${child.pid} ${sid}\n`); const stop = fixtureGuard(t, [records], 100, startFile); // An empty marker is setup, not the start of the observed probe. This wait // exceeds the cleanup budget deliberately; no production bound is changed. await new Promise(resolve => setTimeout(resolve, 500)); assert.equal(child.signalCode, null, 'setup must not consume the probe cleanup budget'); writeFileSync(startFile, 'begin 100.00\n'); const terminal = await Promise.race([exited, new Promise((_, reject) => { const timer = setTimeout(() => reject(new Error('armed fixture guard did not clean up')), 3000); timer.unref(); })]); assert.deepEqual(terminal, [null, 'SIGKILL']); await stop(); });