File size: 2,216 Bytes
fc93158 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | import type { ChildProcess } from "node:child_process";
import { EventEmitter } from "node:events";
import { afterEach, describe, expect, it, vi } from "vitest";
const spawnMock = vi.hoisted(() => vi.fn());
vi.mock("node:child_process", async () => {
const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
return {
...actual,
spawn: spawnMock,
};
});
import { runCommandWithTimeout } from "./exec.js";
function createFakeSpawnedChild() {
const child = new EventEmitter() as EventEmitter & ChildProcess;
const stdout = new EventEmitter();
const stderr = new EventEmitter();
let killed = false;
const kill = vi.fn<(signal?: NodeJS.Signals) => boolean>(() => {
killed = true;
return true;
});
Object.defineProperty(child, "killed", {
get: () => killed,
configurable: true,
});
Object.defineProperty(child, "pid", {
value: 12345,
configurable: true,
});
child.stdout = stdout as ChildProcess["stdout"];
child.stderr = stderr as ChildProcess["stderr"];
child.stdin = null;
child.kill = kill as ChildProcess["kill"];
return { child, stdout, stderr, kill };
}
describe("runCommandWithTimeout no-output timer", () => {
afterEach(() => {
vi.useRealTimers();
vi.restoreAllMocks();
});
it("resets no-output timeout when spawned child keeps emitting stdout", async () => {
vi.useFakeTimers();
const fake = createFakeSpawnedChild();
spawnMock.mockReturnValue(fake.child);
const runPromise = runCommandWithTimeout(["node", "-e", "ignored"], {
timeoutMs: 1_000,
noOutputTimeoutMs: 80,
});
fake.stdout.emit("data", Buffer.from("."));
await vi.advanceTimersByTimeAsync(40);
fake.stdout.emit("data", Buffer.from("."));
await vi.advanceTimersByTimeAsync(40);
fake.stdout.emit("data", Buffer.from("."));
await vi.advanceTimersByTimeAsync(20);
fake.child.emit("close", 0, null);
const result = await runPromise;
expect(result.code ?? 0).toBe(0);
expect(result.termination).toBe("exit");
expect(result.noOutputTimedOut).toBe(false);
expect(result.stdout).toBe("...");
expect(fake.kill).not.toHaveBeenCalled();
});
});
|