also looking at this
test: retain native purge fixture lifecycle observations
#56
38 files
+1820
-172
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -2,19 +2,31 @@ import { mkdtemp, rm, writeFile } from 'node:fs/promises' | ||
| 2 | 2 | import { tmpdir } from 'node:os' |
| 3 | 3 | import { join } from 'node:path' |
| 4 | 4 | |
| 5 | /** Await one guarded native fixture and own its terminal process boundary. */ | |
| 6 | export async function runPurgeQualificationFixture(name: string, timeoutMs: number): Promise<{ code: number, stdout: string, stderr: string }> { | |
| 5 | /** | |
| 6 | * Await one guarded native fixture. Elapsed time includes output drain; the | |
| 7 | * deadline marker and observed signal are separate facts, not a causal verdict. | |
| 8 | */ | |
| 9 | export async function runPurgeQualificationFixture(name: string, timeoutMs: number): Promise<{ code: number, stdout: string, stderr: string, lifecycle: Readonly<{ pid: number, timeoutMs: number, deadlineFired: boolean, elapsedMs: number, signal: string | number | null }> }> { | |
| 7 | 10 | if (!['purge-faults', 'purge-critical', 'purge-budget', 'purge-capacity', 'purge-sql', 'purge-relations', 'purge-seal', 'purge-bounds', 'purge-mixed', 'purge-namespace-identity'].includes(name)) throw new Error('Unknown qualification fixture') |
| 8 | 11 | const root = await mkdtemp(join(tmpdir(), `drone-incident-access-${name}-`)) |
| 9 | 12 | let child: ReturnType<typeof Bun.spawn> | undefined |
| 10 | 13 | try { |
| 11 | 14 | const config = join(root, 'bunfig.toml'); await writeFile(config, 'preload=[]\n') |
| 15 | const started = performance.now() | |
| 16 | let deadlineFired = false | |
| 12 | 17 | const running = Bun.spawn([process.execPath, `--config=${config}`, '--no-env-file', `${import.meta.dir}/../fixtures/public-safety-access/${name}.ts`], { cwd: root, env: { ...process.env, APP_ENV: 'test', NODE_ENV: 'test', DB_CONNECTION: 'sqlite', DB_DATABASE_PATH: join(root, 'access.sqlite') }, stdout: 'pipe', stderr: 'pipe' }) |
| 13 | 18 | child = running |
| 14 | const timer = setTimeout(() => { if (running.exitCode === null) running.kill('SIGKILL') }, timeoutMs) | |
| 19 | const timer = setTimeout(() => { | |
| 20 | if (running.exitCode !== null) return | |
| 21 | deadlineFired = true | |
| 22 | running.kill('SIGKILL') | |
| 23 | console.error('PURGE_FIXTURE_DEADLINE', JSON.stringify({ fixture: name, pid: running.pid, timeoutMs, elapsedMs: performance.now() - started, requestedSignal: 'SIGKILL' })) | |
| 24 | }, timeoutMs) | |
| 15 | 25 | try { |
| 16 | 26 | const [code, stdout, stderr] = await Promise.all([running.exited, new Response(running.stdout).text(), new Response(running.stderr).text()]) |
| 17 | return { code, stdout, stderr } | |
| 27 | const lifecycle = Object.freeze({ pid: running.pid, timeoutMs, deadlineFired, elapsedMs: performance.now() - started, signal: running.signalCode ?? null }) | |
| 28 | if (code !== 0) console.error('PURGE_FIXTURE_EXIT', JSON.stringify({ fixture: name, code, ...lifecycle })) | |
| 29 | return { code, stdout, stderr, lifecycle } | |
| 18 | 30 | } |
| 19 | 31 | finally { clearTimeout(timer) } |
| 20 | 32 | } |