Files
openclaw/src/process/exec.no-output-timer.test.ts

74 lines
2.2 KiB
TypeScript

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();
});
});