mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-07 15:02:55 +00:00
fix(dev): wait for watch-node shutdown
This commit is contained in:
89
test/scripts/watch-node.test.ts
Normal file
89
test/scripts/watch-node.test.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { EventEmitter } from "node:events";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { runWatchMain } from "../../scripts/watch-node.mjs";
|
||||
|
||||
class FakeProcess extends EventEmitter {
|
||||
execPath = process.execPath;
|
||||
pid = 12345;
|
||||
stderr = {
|
||||
write: () => true,
|
||||
};
|
||||
}
|
||||
|
||||
class FakeChild extends EventEmitter {
|
||||
signals: string[] = [];
|
||||
|
||||
kill(signal: string): boolean {
|
||||
this.signals.push(signal);
|
||||
if (signal === "SIGKILL") {
|
||||
this.emit("exit", null, "SIGKILL");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
describe("watch-node shutdown cleanup", () => {
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("waits for the child and escalates when interrupted children ignore SIGTERM", async () => {
|
||||
vi.useFakeTimers();
|
||||
const fakeProcess = new FakeProcess();
|
||||
const child = new FakeChild();
|
||||
let resolvedCode: number | undefined;
|
||||
|
||||
const run = runWatchMain({
|
||||
args: ["gateway"],
|
||||
createWatcher: () => ({ close: async () => {}, on: () => {} }),
|
||||
lockDisabled: true,
|
||||
process: fakeProcess as unknown as NodeJS.Process,
|
||||
spawn: () => child as never,
|
||||
}).then((code) => {
|
||||
resolvedCode = code;
|
||||
return code;
|
||||
});
|
||||
|
||||
fakeProcess.emit("SIGTERM");
|
||||
await vi.advanceTimersByTimeAsync(4_999);
|
||||
expect(resolvedCode).toBeUndefined();
|
||||
expect(child.signals).toEqual(["SIGTERM"]);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
await expect(run).resolves.toBe(143);
|
||||
expect(child.signals).toEqual(["SIGTERM", "SIGKILL"]);
|
||||
});
|
||||
|
||||
it("waits for the auto-doctor child when interrupted during repair", async () => {
|
||||
vi.useFakeTimers();
|
||||
const fakeProcess = new FakeProcess();
|
||||
const runner = new FakeChild();
|
||||
const doctor = new FakeChild();
|
||||
const children = [runner, doctor];
|
||||
let resolvedCode: number | undefined;
|
||||
|
||||
const run = runWatchMain({
|
||||
args: ["gateway"],
|
||||
createWatcher: () => ({ close: async () => {}, on: () => {} }),
|
||||
env: {},
|
||||
lockDisabled: true,
|
||||
process: fakeProcess as unknown as NodeJS.Process,
|
||||
spawn: () => children.shift() as never,
|
||||
}).then((code) => {
|
||||
resolvedCode = code;
|
||||
return code;
|
||||
});
|
||||
|
||||
runner.emit("exit", 1, null);
|
||||
expect(children).toHaveLength(0);
|
||||
|
||||
fakeProcess.emit("SIGTERM");
|
||||
await vi.advanceTimersByTimeAsync(4_999);
|
||||
expect(resolvedCode).toBeUndefined();
|
||||
expect(doctor.signals).toEqual(["SIGTERM"]);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
await expect(run).resolves.toBe(143);
|
||||
expect(doctor.signals).toEqual(["SIGTERM", "SIGKILL"]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user