

















@@ -5,12 +5,14 @@ import { MAX_TIMER_TIMEOUT_MS } from "openclaw/plugin-sdk/number-runtime";
55import { beforeEach, describe, expect, it, vi } from "vitest";
6677const spawnMock = vi.hoisted(() => vi.fn());
8+const spawnSyncMock = vi.hoisted(() => vi.fn());
89const resolveQaNodeExecPathMock = vi.hoisted(() => vi.fn(async () => "/usr/bin/node"));
910const waitForGatewayHealthyMock = vi.hoisted(() => vi.fn(async () => undefined));
1011const waitForTransportReadyMock = vi.hoisted(() => vi.fn(async () => undefined));
11121213vi.mock("node:child_process", () => ({
1314spawn: spawnMock,
15+spawnSync: spawnSyncMock,
1416}));
15171618vi.mock("./node-exec.js", () => ({
@@ -81,6 +83,7 @@ function firstGatewayCall(
8183describe("qa suite runtime agent process helpers", () => {
8284beforeEach(() => {
8385spawnMock.mockReset();
86+spawnSyncMock.mockReset();
8487resolveQaNodeExecPathMock.mockClear();
8588waitForGatewayHealthyMock.mockClear();
8689waitForTransportReadyMock.mockClear();
@@ -182,6 +185,46 @@ describe("qa suite runtime agent process helpers", () => {
182185}
183186});
184187188+it("force-kills timed-out Windows qa cli process trees with taskkill", async () => {
189+const platformDescriptor = Object.getOwnPropertyDescriptor(process, "platform");
190+Object.defineProperty(process, "platform", { value: "win32", configurable: true });
191+try {
192+const child = createSpawnedProcess({ pid: 12345 });
193+spawnMock.mockReturnValue(child);
194+spawnSyncMock.mockReturnValue({ status: 0 });
195+196+const pending = runQaCli(
197+{
198+repoRoot: "/repo",
199+gateway: {
200+tempRoot: "/tmp/runtime",
201+runtimeEnv: { PATH: "/usr/bin" },
202+},
203+primaryModel: "openai/gpt-5.5",
204+alternateModel: "openai/gpt-5.5-mini",
205+providerMode: "mock-openai",
206+} as never,
207+["qa", "suite"],
208+{ timeoutMs: 1 },
209+);
210+const timeoutAssertion = expect(pending).rejects.toThrow(
211+"qa cli timed out: openclaw qa suite",
212+);
213+214+await waitForSpawnCount(1);
215+await timeoutAssertion;
216+expect(spawnSyncMock).toHaveBeenCalledWith("taskkill", ["/PID", "12345", "/T", "/F"], {
217+stdio: "ignore",
218+windowsHide: true,
219+});
220+expect(child.kill).not.toHaveBeenCalled();
221+} finally {
222+if (platformDescriptor) {
223+Object.defineProperty(process, "platform", platformDescriptor);
224+}
225+}
226+});
227+185228it("merges isolated env overrides into qa cli runs", async () => {
186229const child = createSpawnedProcess();
187230spawnMock.mockReturnValue(child);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。