34 lines
1.7 KiB
JavaScript
34 lines
1.7 KiB
JavaScript
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();
|
|
});
|