Skip to content

Commit f8df26a

Browse files
A.R.claude
andcommitted
test(ext): daemon-runtime-spawn polls fast — kills worker-pool flake
ensureBundledDaemon gained an optional { startTimeoutMs } that flows through to ensureDaemon's existing parameter. Production callers (3 sites) call it with no args; behavior unchanged. The spawn-merge test suite now passes startTimeoutMs: 200, dropping per-test runtime from ~15s to ~250ms (5 tests × 1s instead of 5 tests × 15s). Why: the slow test surfaced as a vitest worker-pool crash on Windows + Node 24 push-event CI runs ([vitest-pool]: Worker forks emitted error after the 75s test file completes). The matrix slot's pull_request run completed identically and passed; the difference was runner state at worker teardown after a long-running file. Fixing the test to fail-fast removes the worker stress entirely. Coverage unchanged: spawn() still observed before ensureDaemon throws. The 5 cases (provider env merged, empty {} → no passphrase, hard-coded overrides win, back-compat without provider, no process.env mutation) all still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7a0570e commit f8df26a

2 files changed

Lines changed: 19 additions & 16 deletions

File tree

packages/extension/src/daemon/runtime.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,14 @@ function reapStaleVersionedDaemon(config: RuntimeConfig): void {
116116
removeStaleLock(lockPath);
117117
}
118118

119-
export async function ensureBundledDaemon() {
119+
export async function ensureBundledDaemon(options: { startTimeoutMs?: number } = {}) {
120120
const config = requireRuntimeConfig();
121121
reapStaleVersionedDaemon(config);
122122
return ensureDaemon({
123123
configDir: config.configDir,
124124
spawnDaemon: spawnBundledDaemon,
125125
treatSelfAsZombie: true,
126+
...(options.startTimeoutMs !== undefined ? { startTimeoutMs: options.startTimeoutMs } : {}),
126127
});
127128
}
128129

packages/extension/tests/daemon-runtime-spawn.test.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,13 @@ function fakeChild() {
3939
return { on: vi.fn(), unref: vi.fn() } as unknown as ReturnType<typeof childProcess.spawn>;
4040
}
4141

42-
// ensureBundledDaemon polls the (mocked, never-actually-running) daemon for
43-
// up to ~15s before throwing. Each test catches that throw and asserts on
44-
// the captured spawn() options — so we just need a per-test timeout that
45-
// exceeds the launcher's 15s deadline.
46-
const TEST_TIMEOUT_MS = 20_000;
42+
// ensureBundledDaemon would normally poll the (mocked, never-actually-
43+
// running) daemon for ~15s before throwing. Each test catches that throw
44+
// and asserts on the captured spawn() options. We pass a tiny
45+
// startTimeoutMs (200ms) so the polling loop fails fast — this keeps the
46+
// suite under ~2s instead of ~75s and avoids vitest worker-pool stress
47+
// on Windows + Node 24 CI runners that surfaced as flaky failures.
48+
const FAST_DEADLINE_MS = 200;
4749

4850
describe("spawnBundledDaemon merges buildDaemonEnv result", () => {
4951
beforeEach(() => {
@@ -62,13 +64,13 @@ describe("spawnBundledDaemon merges buildDaemonEnv result", () => {
6264
bundledVersion: "0.8.41",
6365
buildDaemonEnv: async () => ({ PERPLEXITY_VAULT_PASSPHRASE: "test-pass" }),
6466
});
65-
try { await ensureBundledDaemon(); } catch { /* health-check failure is expected */ }
67+
try { await ensureBundledDaemon({ startTimeoutMs: FAST_DEADLINE_MS }); } catch { /* health-check failure is expected */ }
6668
expect(spawnMock).toHaveBeenCalled();
6769
const opts = spawnMock.mock.calls[0]?.[2] as { env: Record<string, string> };
6870
expect(opts.env.PERPLEXITY_VAULT_PASSPHRASE).toBe("test-pass");
6971
expect(opts.env.ELECTRON_RUN_AS_NODE).toBe("1");
7072
expect(opts.env.PERPLEXITY_CONFIG_DIR).toBe("/tmp/perp-test");
71-
}, TEST_TIMEOUT_MS);
73+
});
7274

7375
it("does not set PERPLEXITY_VAULT_PASSPHRASE when provider returns {}", async () => {
7476
configureDaemonRuntime({
@@ -77,10 +79,10 @@ describe("spawnBundledDaemon merges buildDaemonEnv result", () => {
7779
bundledVersion: "0.8.41",
7880
buildDaemonEnv: async () => ({}),
7981
});
80-
try { await ensureBundledDaemon(); } catch { /* expected */ }
82+
try { await ensureBundledDaemon({ startTimeoutMs: FAST_DEADLINE_MS }); } catch { /* expected */ }
8183
const opts = spawnMock.mock.calls[0]?.[2] as { env: Record<string, string> };
8284
expect(opts.env.PERPLEXITY_VAULT_PASSPHRASE).toBeUndefined();
83-
}, TEST_TIMEOUT_MS);
85+
});
8486

8587
it("hard-coded overrides win over provider env", async () => {
8688
configureDaemonRuntime({
@@ -90,22 +92,22 @@ describe("spawnBundledDaemon merges buildDaemonEnv result", () => {
9092
// Provider tries to clobber critical overrides — must not succeed.
9193
buildDaemonEnv: async () => ({ ELECTRON_RUN_AS_NODE: "0", PERPLEXITY_CONFIG_DIR: "/evil" }),
9294
});
93-
try { await ensureBundledDaemon(); } catch { /* expected */ }
95+
try { await ensureBundledDaemon({ startTimeoutMs: FAST_DEADLINE_MS }); } catch { /* expected */ }
9496
const opts = spawnMock.mock.calls[0]?.[2] as { env: Record<string, string> };
9597
expect(opts.env.ELECTRON_RUN_AS_NODE).toBe("1");
9698
expect(opts.env.PERPLEXITY_CONFIG_DIR).toBe("/tmp/perp-test");
97-
}, TEST_TIMEOUT_MS);
99+
});
98100

99101
it("works without a provider (back-compat)", async () => {
100102
configureDaemonRuntime({
101103
configDir: "/tmp/perp-test",
102104
serverPath: "/tmp/perp-test/server.mjs",
103105
bundledVersion: "0.8.41",
104106
});
105-
try { await ensureBundledDaemon(); } catch { /* expected */ }
107+
try { await ensureBundledDaemon({ startTimeoutMs: FAST_DEADLINE_MS }); } catch { /* expected */ }
106108
const opts = spawnMock.mock.calls[0]?.[2] as { env: Record<string, string> };
107109
expect(opts.env.ELECTRON_RUN_AS_NODE).toBe("1");
108-
}, TEST_TIMEOUT_MS);
110+
});
109111

110112
it("does not mutate process.env after spawn", async () => {
111113
delete process.env.PERPLEXITY_VAULT_PASSPHRASE;
@@ -115,7 +117,7 @@ describe("spawnBundledDaemon merges buildDaemonEnv result", () => {
115117
bundledVersion: "0.8.41",
116118
buildDaemonEnv: async () => ({ PERPLEXITY_VAULT_PASSPHRASE: "must-not-leak" }),
117119
});
118-
try { await ensureBundledDaemon(); } catch { /* expected */ }
120+
try { await ensureBundledDaemon({ startTimeoutMs: FAST_DEADLINE_MS }); } catch { /* expected */ }
119121
expect(process.env.PERPLEXITY_VAULT_PASSPHRASE).toBeUndefined();
120-
}, TEST_TIMEOUT_MS);
122+
});
121123
});

0 commit comments

Comments
 (0)