mirror of https://github.com/openclaw/openclaw.git
test: add gateway process helper coverage
This commit is contained in:
parent
7fe5cd26b5
commit
fca6b57037
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const logDebugMock = vi.hoisted(() => vi.fn());
|
||||||
|
|
||||||
|
vi.mock("../logger.js", () => ({
|
||||||
|
logDebug: (...args: unknown[]) => logDebugMock(...args),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { ignoreCiaoCancellationRejection } = await import("./bonjour-ciao.js");
|
||||||
|
|
||||||
|
describe("bonjour-ciao", () => {
|
||||||
|
it("ignores and logs ciao cancellation rejections", () => {
|
||||||
|
expect(
|
||||||
|
ignoreCiaoCancellationRejection(new Error("Ciao announcement cancelled by shutdown")),
|
||||||
|
).toBe(true);
|
||||||
|
expect(logDebugMock).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining("ignoring unhandled ciao rejection"),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps unrelated rejections visible", () => {
|
||||||
|
logDebugMock.mockReset();
|
||||||
|
|
||||||
|
expect(ignoreCiaoCancellationRejection(new Error("boom"))).toBe(false);
|
||||||
|
expect(logDebugMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const spawnSyncMock = vi.hoisted(() => vi.fn());
|
||||||
|
const readFileSyncMock = vi.hoisted(() => vi.fn());
|
||||||
|
const parseCmdScriptCommandLineMock = vi.hoisted(() => vi.fn());
|
||||||
|
const parseProcCmdlineMock = vi.hoisted(() => vi.fn());
|
||||||
|
const isGatewayArgvMock = vi.hoisted(() => vi.fn());
|
||||||
|
const findGatewayPidsOnPortSyncMock = vi.hoisted(() => vi.fn());
|
||||||
|
|
||||||
|
vi.mock("node:child_process", () => ({
|
||||||
|
spawnSync: (...args: unknown[]) => spawnSyncMock(...args),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("node:fs", () => ({
|
||||||
|
default: {
|
||||||
|
readFileSync: (...args: unknown[]) => readFileSyncMock(...args),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../daemon/cmd-argv.js", () => ({
|
||||||
|
parseCmdScriptCommandLine: (...args: unknown[]) => parseCmdScriptCommandLineMock(...args),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./gateway-process-argv.js", () => ({
|
||||||
|
parseProcCmdline: (...args: unknown[]) => parseProcCmdlineMock(...args),
|
||||||
|
isGatewayArgv: (...args: unknown[]) => isGatewayArgvMock(...args),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("./restart-stale-pids.js", () => ({
|
||||||
|
findGatewayPidsOnPortSync: (...args: unknown[]) => findGatewayPidsOnPortSyncMock(...args),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const {
|
||||||
|
findVerifiedGatewayListenerPidsOnPortSync,
|
||||||
|
formatGatewayPidList,
|
||||||
|
readGatewayProcessArgsSync,
|
||||||
|
signalVerifiedGatewayPidSync,
|
||||||
|
} = await import("./gateway-processes.js");
|
||||||
|
|
||||||
|
const originalPlatformDescriptor = Object.getOwnPropertyDescriptor(process, "platform");
|
||||||
|
|
||||||
|
function setPlatform(platform: NodeJS.Platform): void {
|
||||||
|
Object.defineProperty(process, "platform", {
|
||||||
|
value: platform,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("gateway-processes", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
spawnSyncMock.mockReset();
|
||||||
|
readFileSyncMock.mockReset();
|
||||||
|
parseCmdScriptCommandLineMock.mockReset();
|
||||||
|
parseProcCmdlineMock.mockReset();
|
||||||
|
isGatewayArgvMock.mockReset();
|
||||||
|
findGatewayPidsOnPortSyncMock.mockReset();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
if (originalPlatformDescriptor) {
|
||||||
|
Object.defineProperty(process, "platform", originalPlatformDescriptor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reads linux process args from /proc and parses cmdlines", () => {
|
||||||
|
setPlatform("linux");
|
||||||
|
readFileSyncMock.mockReturnValue("node\0dist/index.js\0gateway\0run\0");
|
||||||
|
parseProcCmdlineMock.mockReturnValue(["node", "dist/index.js", "gateway", "run"]);
|
||||||
|
|
||||||
|
expect(readGatewayProcessArgsSync(4242)).toEqual(["node", "dist/index.js", "gateway", "run"]);
|
||||||
|
expect(readFileSyncMock).toHaveBeenCalledWith("/proc/4242/cmdline", "utf8");
|
||||||
|
expect(parseProcCmdlineMock).toHaveBeenCalledWith("node\0dist/index.js\0gateway\0run\0");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reads darwin process args from ps output and returns null on ps failure", () => {
|
||||||
|
setPlatform("darwin");
|
||||||
|
spawnSyncMock
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
error: null,
|
||||||
|
status: 0,
|
||||||
|
stdout: "node /repo/dist/index.js gateway run\n",
|
||||||
|
})
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
error: null,
|
||||||
|
status: 1,
|
||||||
|
stdout: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readGatewayProcessArgsSync(123)).toEqual([
|
||||||
|
"node",
|
||||||
|
"/repo/dist/index.js",
|
||||||
|
"gateway",
|
||||||
|
"run",
|
||||||
|
]);
|
||||||
|
expect(readGatewayProcessArgsSync(124)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back from powershell to wmic for windows process args", () => {
|
||||||
|
setPlatform("win32");
|
||||||
|
spawnSyncMock
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
error: new Error("powershell missing"),
|
||||||
|
status: null,
|
||||||
|
stdout: "",
|
||||||
|
})
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
error: null,
|
||||||
|
status: 0,
|
||||||
|
stdout: "CommandLine=node.exe gateway run\r\n",
|
||||||
|
});
|
||||||
|
parseCmdScriptCommandLineMock.mockReturnValue(["node.exe", "gateway", "run"]);
|
||||||
|
|
||||||
|
expect(readGatewayProcessArgsSync(77)).toEqual(["node.exe", "gateway", "run"]);
|
||||||
|
expect(parseCmdScriptCommandLineMock).toHaveBeenCalledWith("node.exe gateway run");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("signals only verified gateway processes", () => {
|
||||||
|
setPlatform("linux");
|
||||||
|
readFileSyncMock.mockReturnValue("node\0gateway\0");
|
||||||
|
parseProcCmdlineMock.mockReturnValue(["node", "gateway"]);
|
||||||
|
isGatewayArgvMock.mockReturnValueOnce(true).mockReturnValueOnce(false);
|
||||||
|
const killSpy = vi.spyOn(process, "kill").mockImplementation(() => true);
|
||||||
|
|
||||||
|
signalVerifiedGatewayPidSync(500, "SIGTERM");
|
||||||
|
expect(killSpy).toHaveBeenCalledWith(500, "SIGTERM");
|
||||||
|
|
||||||
|
expect(() => signalVerifiedGatewayPidSync(501, "SIGUSR1")).toThrow(
|
||||||
|
/refusing to signal non-gateway process pid 501/,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("dedupes and filters verified gateway listener pids on unix and windows", () => {
|
||||||
|
setPlatform("linux");
|
||||||
|
findGatewayPidsOnPortSyncMock.mockReturnValue([process.pid, 200, 200, 300, -1]);
|
||||||
|
readFileSyncMock.mockReturnValueOnce("openclaw-gateway\0gateway\0");
|
||||||
|
readFileSyncMock.mockReturnValueOnce("python\0-m\0http.server\0");
|
||||||
|
parseProcCmdlineMock
|
||||||
|
.mockReturnValueOnce(["openclaw-gateway", "gateway"])
|
||||||
|
.mockReturnValueOnce(["python", "-m", "http.server"]);
|
||||||
|
isGatewayArgvMock.mockReturnValueOnce(true).mockReturnValueOnce(false);
|
||||||
|
|
||||||
|
expect(findVerifiedGatewayListenerPidsOnPortSync(18789)).toEqual([200]);
|
||||||
|
setPlatform("win32");
|
||||||
|
spawnSyncMock
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
error: null,
|
||||||
|
status: 0,
|
||||||
|
stdout: "200\r\n200\r\n0\r\n",
|
||||||
|
})
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
error: null,
|
||||||
|
status: 0,
|
||||||
|
stdout: "node.exe gateway run",
|
||||||
|
});
|
||||||
|
parseCmdScriptCommandLineMock.mockReturnValue(["node.exe", "gateway", "run"]);
|
||||||
|
isGatewayArgvMock.mockReturnValue(true);
|
||||||
|
|
||||||
|
expect(findVerifiedGatewayListenerPidsOnPortSync(18789)).toEqual([200]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats pid lists as comma-separated output", () => {
|
||||||
|
expect(formatGatewayPidList([1, 2, 3])).toBe("1, 2, 3");
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue