mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-14 08:28:34 +00:00
fix(infra): land #29078 from @cathrynlavery with restart fallback
Co-authored-by: Cathryn Lavery <cathryn@littlemight.com>
This commit is contained in:
@@ -3,10 +3,14 @@ import { captureFullEnv } from "../test-utils/env.js";
|
||||
import { SUPERVISOR_HINT_ENV_VARS } from "./supervisor-markers.js";
|
||||
|
||||
const spawnMock = vi.hoisted(() => vi.fn());
|
||||
const triggerOpenClawRestartMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("node:child_process", () => ({
|
||||
spawn: (...args: unknown[]) => spawnMock(...args),
|
||||
}));
|
||||
vi.mock("./restart.js", () => ({
|
||||
triggerOpenClawRestart: (...args: unknown[]) => triggerOpenClawRestartMock(...args),
|
||||
}));
|
||||
|
||||
import { restartGatewayProcessWithFreshPid } from "./process-respawn.js";
|
||||
|
||||
@@ -30,6 +34,7 @@ afterEach(() => {
|
||||
process.argv = [...originalArgv];
|
||||
process.execArgv = [...originalExecArgv];
|
||||
spawnMock.mockClear();
|
||||
triggerOpenClawRestartMock.mockClear();
|
||||
if (originalPlatformDescriptor) {
|
||||
Object.defineProperty(process, "platform", originalPlatformDescriptor);
|
||||
}
|
||||
@@ -56,40 +61,33 @@ describe("restartGatewayProcessWithFreshPid", () => {
|
||||
expect(spawnMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("schedules detached launchctl kickstart on macOS when launchd label is set", () => {
|
||||
it("runs launchd kickstart helper on macOS when launchd label is set", () => {
|
||||
setPlatform("darwin");
|
||||
process.env.LAUNCH_JOB_LABEL = "ai.openclaw.gateway";
|
||||
process.env.OPENCLAW_LAUNCHD_LABEL = "ai.openclaw.gateway";
|
||||
const unrefMock = vi.fn();
|
||||
spawnMock.mockReturnValue({ unref: unrefMock, on: vi.fn() });
|
||||
triggerOpenClawRestartMock.mockReturnValue({ ok: true, method: "launchctl" });
|
||||
|
||||
const result = restartGatewayProcessWithFreshPid();
|
||||
|
||||
expect(result.mode).toBe("supervised");
|
||||
expect(spawnMock).toHaveBeenCalledWith(
|
||||
"launchctl",
|
||||
["kickstart", "-k", expect.stringContaining("ai.openclaw.gateway")],
|
||||
expect.objectContaining({ detached: true, stdio: "ignore" }),
|
||||
);
|
||||
expect(unrefMock).toHaveBeenCalledOnce();
|
||||
expect(triggerOpenClawRestartMock).toHaveBeenCalledOnce();
|
||||
expect(spawnMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("still returns supervised even if kickstart spawn throws", () => {
|
||||
it("returns failed when launchd kickstart helper fails", () => {
|
||||
setPlatform("darwin");
|
||||
process.env.LAUNCH_JOB_LABEL = "ai.openclaw.gateway";
|
||||
process.env.OPENCLAW_LAUNCHD_LABEL = "ai.openclaw.gateway";
|
||||
spawnMock.mockImplementation((...args: unknown[]) => {
|
||||
const [cmd] = args as [string];
|
||||
if (cmd === "launchctl") {
|
||||
throw new Error("spawn failed");
|
||||
}
|
||||
return { unref: vi.fn(), on: vi.fn() };
|
||||
triggerOpenClawRestartMock.mockReturnValue({
|
||||
ok: false,
|
||||
method: "launchctl",
|
||||
detail: "spawn failed",
|
||||
});
|
||||
|
||||
const result = restartGatewayProcessWithFreshPid();
|
||||
|
||||
// Kickstart is best-effort; failure should not block supervised exit
|
||||
expect(result.mode).toBe("supervised");
|
||||
expect(result.mode).toBe("failed");
|
||||
expect(result.detail).toContain("spawn failed");
|
||||
});
|
||||
|
||||
it("does not schedule kickstart on non-darwin platforms", () => {
|
||||
@@ -100,6 +98,7 @@ describe("restartGatewayProcessWithFreshPid", () => {
|
||||
const result = restartGatewayProcessWithFreshPid();
|
||||
|
||||
expect(result.mode).toBe("supervised");
|
||||
expect(triggerOpenClawRestartMock).not.toHaveBeenCalled();
|
||||
expect(spawnMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -127,16 +126,11 @@ describe("restartGatewayProcessWithFreshPid", () => {
|
||||
clearSupervisorHints();
|
||||
setPlatform("darwin");
|
||||
process.env.OPENCLAW_LAUNCHD_LABEL = "ai.openclaw.gateway";
|
||||
const unrefMock = vi.fn();
|
||||
spawnMock.mockReturnValue({ unref: unrefMock, on: vi.fn() });
|
||||
triggerOpenClawRestartMock.mockReturnValue({ ok: true, method: "launchctl" });
|
||||
const result = restartGatewayProcessWithFreshPid();
|
||||
expect(result.mode).toBe("supervised");
|
||||
expect(spawnMock).toHaveBeenCalledWith(
|
||||
"launchctl",
|
||||
expect.arrayContaining(["kickstart", "-k"]),
|
||||
expect.objectContaining({ detached: true }),
|
||||
);
|
||||
expect(unrefMock).toHaveBeenCalledOnce();
|
||||
expect(triggerOpenClawRestartMock).toHaveBeenCalledOnce();
|
||||
expect(spawnMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns supervised when OPENCLAW_SYSTEMD_UNIT is set", () => {
|
||||
|
||||
Reference in New Issue
Block a user