@@ -136,6 +136,50 @@ describe("plugin lifecycle matrix probe", () => {
|
136 | 136 | } |
137 | 137 | }); |
138 | 138 | |
| 139 | +it("force-kills timed Windows commands with taskkill when graceful taskkill fails", async () => { |
| 140 | +vi.useFakeTimers(); |
| 141 | +const platformDescriptor = Object.getOwnPropertyDescriptor(process, "platform"); |
| 142 | +Object.defineProperty(process, "platform", { value: "win32", configurable: true }); |
| 143 | +try { |
| 144 | +const child = Object.assign(new FakeCommandChild(), { pid: 12345 }); |
| 145 | +const taskkillImpl = vi |
| 146 | +.fn() |
| 147 | +.mockReturnValueOnce({ status: 1 }) |
| 148 | +.mockImplementationOnce(() => { |
| 149 | +queueMicrotask(() => child.emit("exit", null, "SIGTERM")); |
| 150 | +return { status: 0 }; |
| 151 | +}); |
| 152 | +const runPromise = probeTesting.runCommand("fake-command", ["install"], { |
| 153 | +spawnImpl: (() => child) as unknown as typeof import("node:child_process").spawn, |
| 154 | + taskkillImpl, |
| 155 | +timeoutKillGraceMs: 100, |
| 156 | +timeoutMs: 10, |
| 157 | +}); |
| 158 | +const runError = runPromise.catch((error: unknown) => error); |
| 159 | + |
| 160 | +await vi.advanceTimersByTimeAsync(10); |
| 161 | + |
| 162 | +expect(taskkillImpl).toHaveBeenNthCalledWith(1, "taskkill", ["/PID", "12345", "/T"], { |
| 163 | +stdio: "ignore", |
| 164 | +windowsHide: true, |
| 165 | +}); |
| 166 | +expect(taskkillImpl).toHaveBeenNthCalledWith(2, "taskkill", ["/PID", "12345", "/T", "/F"], { |
| 167 | +stdio: "ignore", |
| 168 | +windowsHide: true, |
| 169 | +}); |
| 170 | +expect(child.signals).toEqual([]); |
| 171 | + |
| 172 | +const error = await runError; |
| 173 | +expect(error).toBeInstanceOf(Error); |
| 174 | +expect((error as Error).message).toBe("fake-command install timed out after 10ms"); |
| 175 | +} finally { |
| 176 | +if (platformDescriptor) { |
| 177 | +Object.defineProperty(process, "platform", platformDescriptor); |
| 178 | +} |
| 179 | +vi.useRealTimers(); |
| 180 | +} |
| 181 | +}); |
| 182 | + |
139 | 183 | it("keeps fallback SIGKILL armed for ignored-stdio descendants", async () => { |
140 | 184 | if (process.platform === "win32") { |
141 | 185 | return; |
|