|
1 | 1 | // Daemon program argument tests cover CLI argument construction for services. |
2 | 2 | import path from "node:path"; |
3 | 3 | import { afterEach, describe, expect, it, vi } from "vitest"; |
| 4 | +import { resetWindowsInstallRootsForTests } from "../infra/windows-install-roots.js"; |
| 5 | +import { withMockedWindowsPlatform } from "../test-utils/vitest-spies.js"; |
4 | 6 |
|
5 | 7 | const childProcessMocks = vi.hoisted(() => ({ |
6 | 8 | execFileSync: vi.fn(), |
@@ -43,6 +45,8 @@ const originalArgv = [...process.argv]; |
43 | 45 | afterEach(() => { |
44 | 46 | process.argv = [...originalArgv]; |
45 | 47 | vi.resetAllMocks(); |
| 48 | + vi.unstubAllEnvs(); |
| 49 | + resetWindowsInstallRootsForTests(); |
46 | 50 | }); |
47 | 51 |
|
48 | 52 | describe("resolveGatewayProgramArguments", () => { |
@@ -179,6 +183,39 @@ describe("resolveGatewayProgramArguments", () => { |
179 | 183 | expect(result.workingDirectory).toBe(path.resolve("/repo")); |
180 | 184 | }); |
181 | 185 |
|
| 186 | + it("uses trusted Windows where.exe when resolving dev runtime binaries", async () => { |
| 187 | + const repoIndexPath = path.resolve("/repo/src/index.ts"); |
| 188 | + const repoEntryPath = path.resolve("/repo/src/entry.ts"); |
| 189 | + process.argv = [String.raw`D:\nodejs\node.exe`, repoIndexPath]; |
| 190 | + vi.stubEnv("SystemRoot", String.raw`D:\Windows`); |
| 191 | + resetWindowsInstallRootsForTests({ queryRegistryValue: () => null }); |
| 192 | + fsMocks.realpath.mockResolvedValue(repoIndexPath); |
| 193 | + fsMocks.access.mockResolvedValue(undefined); |
| 194 | + childProcessMocks.execFileSync.mockReturnValue(String.raw`D:\Tools\bun.exe` + "\r\n"); |
| 195 | + |
| 196 | + let result: Awaited<ReturnType<typeof resolveGatewayProgramArguments>> | undefined; |
| 197 | + await withMockedWindowsPlatform(async () => { |
| 198 | + result = await resolveGatewayProgramArguments({ |
| 199 | + dev: true, |
| 200 | + port: 18789, |
| 201 | + runtime: "bun", |
| 202 | + }); |
| 203 | + }); |
| 204 | + |
| 205 | + expect(childProcessMocks.execFileSync).toHaveBeenCalledWith( |
| 206 | + path.win32.join(String.raw`D:\Windows`, "System32", "where.exe"), |
| 207 | + ["bun"], |
| 208 | + { encoding: "utf8" }, |
| 209 | + ); |
| 210 | + expect(result?.programArguments).toEqual([ |
| 211 | + String.raw`D:\Tools\bun.exe`, |
| 212 | + repoEntryPath, |
| 213 | + "gateway", |
| 214 | + "--port", |
| 215 | + "18789", |
| 216 | + ]); |
| 217 | + }); |
| 218 | + |
182 | 219 | it("uses an executable wrapper when provided", async () => { |
183 | 220 | const wrapperPath = path.resolve("/usr/local/bin/openclaw-doppler"); |
184 | 221 | fsMocks.stat.mockResolvedValue({ isFile: () => true } as never); |
|
0 commit comments