@@ -4,11 +4,12 @@ import fs from "node:fs";
|
4 | 4 | import path from "node:path"; |
5 | 5 | import { setTimeout as delay } from "node:timers/promises"; |
6 | 6 | import { pathToFileURL } from "node:url"; |
7 | | -import { describe, expect, it } from "vitest"; |
| 7 | +import { describe, expect, it, vi } from "vitest"; |
8 | 8 | import { |
9 | 9 | createManagedCommandSpawnSpec, |
10 | 10 | runManagedCommand, |
11 | 11 | signalExitCode, |
| 12 | +terminateManagedChild, |
12 | 13 | } from "../../scripts/lib/managed-child-process.mjs"; |
13 | 14 | import { createScriptTestHarness } from "./test-helpers.js"; |
14 | 15 | |
@@ -110,6 +111,31 @@ describe("managed-child-process", () => {
|
110 | 111 | ).toThrow("unsafe Windows cmd.exe argument detected"); |
111 | 112 | }); |
112 | 113 | |
| 114 | +it("signals Windows managed process trees with taskkill", () => { |
| 115 | +const child = { |
| 116 | +kill: vi.fn(), |
| 117 | +pid: 12345, |
| 118 | +}; |
| 119 | +const runTaskkill = vi.fn(() => ({ error: undefined, status: 0 })); |
| 120 | + |
| 121 | +terminateManagedChild(child, "SIGTERM", { |
| 122 | +platform: "win32", |
| 123 | + runTaskkill, |
| 124 | +}); |
| 125 | +expect(runTaskkill).toHaveBeenNthCalledWith(1, "taskkill", ["/PID", "12345", "/T"], { |
| 126 | +stdio: "ignore", |
| 127 | +}); |
| 128 | + |
| 129 | +terminateManagedChild(child, "SIGKILL", { |
| 130 | +platform: "win32", |
| 131 | + runTaskkill, |
| 132 | +}); |
| 133 | +expect(runTaskkill).toHaveBeenNthCalledWith(2, "taskkill", ["/PID", "12345", "/T", "/F"], { |
| 134 | +stdio: "ignore", |
| 135 | +}); |
| 136 | +expect(child.kill).not.toHaveBeenCalled(); |
| 137 | +}); |
| 138 | + |
113 | 139 | it("shares process signal listeners across parallel managed commands", async () => { |
114 | 140 | const signals = ["SIGHUP", "SIGINT", "SIGTERM"] as const; |
115 | 141 | const baseline = new Map(signals.map((signal) => [signal, process.listenerCount(signal)])); |
|