import { mkdtemp, readFile, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; import { runProviderProcess } from "../../../scripts/lib/provider-process-runner.ts"; describe("CI-runner provider process-group lifecycle", () => { it("kills and reaps a stubborn provider process group including its descendant", async () => { const root = await mkdtemp(path.join(tmpdir(), "provider-process-group-")); const descendantPidPath = path.join(root, "descendant.pid"); try { const source = [ "const { spawn } = require('node:child_process');", "const { writeFileSync } = require('node:fs');", "const child = spawn(process.execPath, ['-e', `process.on('SIGTERM', () => {}); setInterval(() => {}, 1000)`], { stdio: 'ignore' });", "writeFileSync(process.env.DESCENDANT_PID_PATH, String(child.pid));", "process.on('SIGTERM', () => {});", "setInterval(() => {}, 1000);", ].join("\n"); const running = runProviderProcess({ executable: process.execPath, arguments: ["-e", source], environment: { PATH: process.env.PATH, DESCENDANT_PID_PATH: descendantPidPath, }, timeoutMs: 250, }); await expect(running).rejects.toThrow(/timed out.*process close/u); const descendantPid = Number(await readFile(descendantPidPath, "utf8")); expect(Number.isSafeInteger(descendantPid) && descendantPid > 0).toBe(true); expect(() => process.kill(descendantPid, 0)).toThrow(/ESRCH|no such process/u); } finally { await rm(root, { recursive: true, force: true }); } }); });