






















@@ -201,7 +201,7 @@ describe("watch-node script", () => {
201201const { child, spawn, watcher, createWatcher, fakeProcess } = createWatchHarness();
202202203203const runPromise = runWatch({
204-args: ["gateway", "--force", "--help"],
204+args: ["config", "validate"],
205205 createWatcher,
206206lockDisabled: true,
207207process: fakeProcess,
@@ -217,6 +217,66 @@ describe("watch-node script", () => {
217217expect(fakeProcess.listenerCount("SIGTERM")).toBe(0);
218218});
219219220+it("runs doctor once and restarts when gateway exits nonzero", async () => {
221+const gatewayA = Object.assign(new EventEmitter(), { kill: vi.fn() });
222+const doctor = Object.assign(new EventEmitter(), { kill: vi.fn() });
223+const gatewayB = Object.assign(new EventEmitter(), { kill: vi.fn() });
224+const spawn = vi
225+.fn()
226+.mockReturnValueOnce(gatewayA)
227+.mockReturnValueOnce(doctor)
228+.mockReturnValueOnce(gatewayB);
229+const { watcher, fakeProcess, runPromise } = startWatchRun({ spawn });
230+231+gatewayA.emit("exit", 1, null);
232+await new Promise((resolve) => setImmediate(resolve));
233+234+expect(spawn).toHaveBeenCalledTimes(2);
235+expect(spawn).toHaveBeenNthCalledWith(
236+2,
237+"/usr/local/bin/node",
238+["scripts/run-node.mjs", "doctor", "--fix", "--non-interactive"],
239+expect.objectContaining({ stdio: "inherit" }),
240+);
241+242+doctor.emit("exit", 0, null);
243+await new Promise((resolve) => setImmediate(resolve));
244+245+expect(spawn).toHaveBeenCalledTimes(3);
246+expect(spawn).toHaveBeenNthCalledWith(
247+3,
248+"/usr/local/bin/node",
249+["scripts/run-node.mjs", "gateway", "--force"],
250+expect.objectContaining({ stdio: "inherit" }),
251+);
252+253+fakeProcess.emit("SIGINT");
254+const exitCode = await runPromise;
255+expect(exitCode).toBe(130);
256+expect(gatewayB.kill).toHaveBeenCalledWith("SIGTERM");
257+expect(watcher.close).toHaveBeenCalledTimes(1);
258+});
259+260+it("does not run doctor after a gateway failure when auto doctor is disabled", async () => {
261+const { child, spawn, watcher, createWatcher, fakeProcess } = createWatchHarness();
262+263+const runPromise = runWatch({
264+args: ["gateway", "--force"],
265+ createWatcher,
266+env: { OPENCLAW_GATEWAY_WATCH_AUTO_DOCTOR: "0" },
267+lockDisabled: true,
268+process: fakeProcess,
269+ spawn,
270+});
271+272+child.emit("exit", 1, null);
273+const exitCode = await runPromise;
274+275+expect(exitCode).toBe(1);
276+expect(spawn).toHaveBeenCalledTimes(1);
277+expect(watcher.close).toHaveBeenCalledTimes(1);
278+});
279+220280it("restarts when the runner exits with a SIGTERM-derived code unexpectedly", async () => {
221281const childA = Object.assign(new EventEmitter(), {
222282kill: vi.fn(),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。