import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { describe, expect, it, vi } from "vitest"; import "./test-helpers/fast-core-tools.js"; import { createOpenClawTools } from "./openclaw-tools.js"; vi.mock("./tools/gateway.js", () => ({ callGatewayTool: vi.fn(async (method: string) => { if (method === "config.get") { return { hash: "hash-1" }; } return { ok: true }; }), })); describe("gateway tool", () => { it("schedules SIGUSR1 restart", async () => { vi.useFakeTimers(); const kill = vi.spyOn(process, "kill").mockImplementation(() => true); const previousStateDir = process.env.OPENCLAW_STATE_DIR; const previousProfile = process.env.OPENCLAW_PROFILE; const stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-test-")); process.env.OPENCLAW_STATE_DIR = stateDir; process.env.OPENCLAW_PROFILE = "isolated"; try { const tool = createOpenClawTools({ config: { commands: { restart: true } }, }).find((candidate) => candidate.name === "gateway"); expect(tool).toBeDefined(); if (!tool) throw new Error("missing gateway tool"); const result = await tool.execute("call1", { action: "restart", delayMs: 0, }); expect(result.details).toMatchObject({ ok: true, pid: process.pid, signal: "SIGUSR1", delayMs: 0, }); const sentinelPath = path.join(stateDir, "restart-sentinel.json"); const raw = await fs.readFile(sentinelPath, "utf-8"); const parsed = JSON.parse(raw) as { payload?: { kind?: string; doctorHint?: string | null }; }; expect(parsed.payload?.kind).toBe("restart"); expect(parsed.payload?.doctorHint).toBe( "Run: openclaw --profile isolated doctor --non-interactive", ); expect(kill).not.toHaveBeenCalled(); await vi.runAllTimersAsync(); expect(kill).toHaveBeenCalledWith(process.pid, "SIGUSR1"); } finally { kill.mockRestore(); vi.useRealTimers(); if (previousStateDir === undefined) { delete process.env.OPENCLAW_STATE_DIR; } else { process.env.OPENCLAW_STATE_DIR = previousStateDir; } if (previousProfile === undefined) { delete process.env.OPENCLAW_PROFILE; } else { process.env.OPENCLAW_PROFILE = previousProfile; } } }); it("passes config.apply through gateway call", async () => { const { callGatewayTool } = await import("./tools/gateway.js"); const tool = createOpenClawTools({ agentSessionKey: "agent:main:whatsapp:dm:+15555550123", }).find((candidate) => candidate.name === "gateway"); expect(tool).toBeDefined(); if (!tool) throw new Error("missing gateway tool"); const raw = '{\n agents: { defaults: { workspace: "~/openclaw" } }\n}\n'; await tool.execute("call2", { action: "config.apply", raw, }); expect(callGatewayTool).toHaveBeenCalledWith("config.get", expect.any(Object), {}); expect(callGatewayTool).toHaveBeenCalledWith( "config.apply", expect.any(Object), expect.objectContaining({ raw: raw.trim(), baseHash: "hash-1", sessionKey: "agent:main:whatsapp:dm:+15555550123", }), ); }); it("passes config.patch through gateway call", async () => { const { callGatewayTool } = await import("./tools/gateway.js"); const tool = createOpenClawTools({ agentSessionKey: "agent:main:whatsapp:dm:+15555550123", }).find((candidate) => candidate.name === "gateway"); expect(tool).toBeDefined(); if (!tool) throw new Error("missing gateway tool"); const raw = '{\n channels: { telegram: { groups: { "*": { requireMention: false } } } }\n}\n'; await tool.execute("call4", { action: "config.patch", raw, }); expect(callGatewayTool).toHaveBeenCalledWith("config.get", expect.any(Object), {}); expect(callGatewayTool).toHaveBeenCalledWith( "config.patch", expect.any(Object), expect.objectContaining({ raw: raw.trim(), baseHash: "hash-1", sessionKey: "agent:main:whatsapp:dm:+15555550123", }), ); }); it("passes update.run through gateway call", async () => { const { callGatewayTool } = await import("./tools/gateway.js"); const tool = createOpenClawTools({ agentSessionKey: "agent:main:whatsapp:dm:+15555550123", }).find((candidate) => candidate.name === "gateway"); expect(tool).toBeDefined(); if (!tool) throw new Error("missing gateway tool"); await tool.execute("call3", { action: "update.run", note: "test update", }); expect(callGatewayTool).toHaveBeenCalledWith( "update.run", expect.any(Object), expect.objectContaining({ note: "test update", sessionKey: "agent:main:whatsapp:dm:+15555550123", }), ); }); });