Files
ThothII/backend/test/pi-spawn-args.test.ts

60 lines
2.5 KiB
TypeScript

import { test, expect, vi } from "vitest";
import { EventEmitter } from "node:events";
// Mock node:child_process so the PRODUCTION spawnFn (no injected spawnFn) is exercised
// without launching a real pi. Per-file mock — kept out of pi-process-manager.test.ts,
// which deliberately spawns the real fake_pi.
vi.mock("node:child_process", () => ({
spawn: vi.fn(() => {
const ch: any = new EventEmitter();
ch.stdout = new EventEmitter();
ch.stderr = new EventEmitter();
ch.stderr.resume = () => {};
ch.stdin = { write: () => true };
ch.kill = () => {};
return ch;
}),
}));
import { spawn as nodeSpawn } from "node:child_process";
import { PiProcessManager } from "../src/pi/pi-process-manager.js";
import { loadConfig } from "../src/config.js";
test("production spawnFn launches `pi --mode rpc` with no --approve (pi 0.73 dropped it)", async () => {
(nodeSpawn as any).mockClear();
// loadConfig({}) leaves provider/model/thinking unset → spawnFor skips the rpc
// handshake and just spawns + sends the prompt, so the mocked child never hangs.
const cfg = loadConfig({});
const mgr = new PiProcessManager(cfg); // NO injected spawnFn → uses the production spawnFn
await mgr.spawnFor("s1", {});
const [bin, args] = (nodeSpawn as any).mock.calls[0];
expect(bin).toBe(cfg.piBin);
expect(args).toEqual(["--mode", "rpc"]);
expect(args).not.toContain("--approve");
mgr.teardown("s1");
});
test("Pi child replaces stale principal env and omits absent display names", async () => {
const saved = Object.fromEntries([
"THT_PRINCIPAL_ISSUER", "THT_PRINCIPAL_SUBJECT", "THT_PRINCIPAL_DISPLAY_NAME", "THT_PRINCIPAL_IS_ADMIN",
].map((key) => [key, process.env[key]]));
Object.assign(process.env, {
THT_PRINCIPAL_ISSUER: "stale", THT_PRINCIPAL_SUBJECT: "stale", THT_PRINCIPAL_DISPLAY_NAME: "stale",
THT_PRINCIPAL_IS_ADMIN: "true",
});
try {
(nodeSpawn as any).mockClear();
const mgr = new PiProcessManager(loadConfig({}));
await mgr.spawnFor("s-principal", { principal: { issuer: "portal", subject: "42", isAdmin: false } });
const env = (nodeSpawn as any).mock.calls[0][2].env;
expect(env).toMatchObject({
THT_PRINCIPAL_ISSUER: "portal", THT_PRINCIPAL_SUBJECT: "42", THT_PRINCIPAL_IS_ADMIN: "false",
});
expect(env).not.toHaveProperty("THT_PRINCIPAL_DISPLAY_NAME");
mgr.teardown("s-principal");
} finally {
for (const [key, value] of Object.entries(saved)) {
if (value === undefined) delete process.env[key]; else process.env[key] = value;
}
}
});