



























@@ -22,6 +22,8 @@ const readPackageName = vi.fn();
2222const readPackageVersion = vi.fn();
2323const resolveGlobalManager = vi.fn();
2424const serviceLoaded = vi.fn();
25+const serviceStop = vi.fn();
26+const serviceRestart = vi.fn();
2527const prepareRestartScript = vi.fn();
2628const runRestartScript = vi.fn();
2729const mockedRunDaemonInstall = vi.fn();
@@ -187,6 +189,8 @@ vi.mock("../daemon/service.js", () => ({
187189isLoaded: (...args: unknown[]) => serviceLoaded(...args),
188190readCommand: (...args: unknown[]) => serviceReadCommand(...args),
189191readRuntime: (...args: unknown[]) => serviceReadRuntime(...args),
192+stop: (...args: unknown[]) => serviceStop(...args),
193+restart: (...args: unknown[]) => serviceRestart(...args),
190194})),
191195}));
192196@@ -470,6 +474,8 @@ describe("update-cli", () => {
470474readPackageName.mockResolvedValue("openclaw");
471475readPackageVersion.mockResolvedValue("1.0.0");
472476resolveGlobalManager.mockResolvedValue("npm");
477+serviceStop.mockResolvedValue(undefined);
478+serviceRestart.mockResolvedValue({ outcome: "completed" });
473479serviceLoaded.mockResolvedValue(false);
474480serviceReadCommand.mockImplementation(async () =>
475481(await serviceLoaded()) ? { programArguments: ["openclaw", "gateway", "run"] } : null,
@@ -1389,6 +1395,85 @@ describe("update-cli", () => {
13891395);
13901396});
139113971398+it("stops a running managed gateway before package replacement", async () => {
1399+const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-stop-service-"));
1400+const nodeModules = path.join(tempDir, "node_modules");
1401+const pkgRoot = path.join(nodeModules, "openclaw");
1402+const entryPath = path.join(pkgRoot, "dist", "index.js");
1403+mockPackageInstallStatus(pkgRoot);
1404+await fs.mkdir(path.dirname(entryPath), { recursive: true });
1405+await fs.writeFile(
1406+path.join(pkgRoot, "package.json"),
1407+JSON.stringify({ name: "openclaw", version: "2026.4.21" }),
1408+"utf-8",
1409+);
1410+await fs.writeFile(entryPath, "export {};\n", "utf-8");
1411+await writePackageDistInventory(pkgRoot);
1412+serviceReadCommand.mockResolvedValue({
1413+programArguments: ["openclaw", "gateway", "run"],
1414+environment: {
1415+OPENCLAW_SERVICE_MARKER: "openclaw",
1416+OPENCLAW_SERVICE_KIND: "gateway",
1417+},
1418+});
1419+serviceLoaded.mockResolvedValue(true);
1420+serviceReadRuntime.mockResolvedValue({
1421+status: "running",
1422+pid: 4242,
1423+state: "running",
1424+});
1425+pathExists.mockImplementation(async (candidate: string) => {
1426+try {
1427+await fs.access(candidate);
1428+return true;
1429+} catch {
1430+return false;
1431+}
1432+});
1433+vi.mocked(runCommandWithTimeout).mockImplementation(async (argv) => {
1434+if (Array.isArray(argv) && argv[0] === "npm" && argv[1] === "root" && argv[2] === "-g") {
1435+return {
1436+stdout: `${nodeModules}\n`,
1437+stderr: "",
1438+code: 0,
1439+signal: null,
1440+killed: false,
1441+termination: "exit",
1442+};
1443+}
1444+return {
1445+stdout: "",
1446+stderr: "",
1447+code: 0,
1448+signal: null,
1449+killed: false,
1450+termination: "exit",
1451+};
1452+});
1453+1454+await updateCommand({ yes: true });
1455+1456+const npmInstallCallIndex = vi
1457+.mocked(runCommandWithTimeout)
1458+.mock.calls.findIndex(
1459+(call) => Array.isArray(call[0]) && call[0][0] === "npm" && call[0][1] === "i",
1460+);
1461+const npmInstallCallOrder =
1462+vi.mocked(runCommandWithTimeout).mock.invocationCallOrder[npmInstallCallIndex];
1463+expect(serviceStop).toHaveBeenCalledWith(
1464+expect.objectContaining({
1465+env: expect.objectContaining({
1466+OPENCLAW_SERVICE_MARKER: "openclaw",
1467+OPENCLAW_SERVICE_KIND: "gateway",
1468+}),
1469+}),
1470+);
1471+const serviceStopCallOrder = serviceStop.mock.invocationCallOrder[0];
1472+expect(serviceStopCallOrder).toBeDefined();
1473+expect(npmInstallCallOrder).toBeDefined();
1474+expect(serviceStopCallOrder).toBeLessThan(npmInstallCallOrder);
1475+});
1476+13921477it("refreshes package installs even when the current version already matches the target", async () => {
13931478const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-current-"));
13941479const nodeModules = path.join(tempDir, "node_modules");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。