From e26f0339d18cbf2f6bf33ff128078d86f0d93809 Mon Sep 17 00:00:00 2001 From: "paseo-bot[bot]" <266920839+paseo-bot[bot]@users.noreply.github.com> Date: Sat, 17 Oct 2026 18:56:26 +0200 Subject: [PATCH] test(acp): start hung-session deadlines after initialization Wait for the fake agent to receive session/new before advancing its diagnostic deadline. Slow process startup must not turn a session-timeout assertion into an initialization timeout. --- .../generic-acp-agent.diagnostic.test.ts | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/server/src/server/agent/providers/generic-acp-agent.diagnostic.test.ts b/packages/server/src/server/agent/providers/generic-acp-agent.diagnostic.test.ts index d70117d57d..e3cc9628ab 100644 --- a/packages/server/src/server/agent/providers/generic-acp-agent.diagnostic.test.ts +++ b/packages/server/src/server/agent/providers/generic-acp-agent.diagnostic.test.ts @@ -3,7 +3,8 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; -import { describe, expect, test } from "vitest"; +import { describe, expect, test, vi } from "vitest"; +import { setTimeout as delay } from "node:timers/promises"; import { createTestLogger } from "../../../test-utils/test-logger.js"; import { runProviderRefreshWithDeadline } from "../provider-refresh-deadline.js"; @@ -203,16 +204,28 @@ describe("GenericACPAgentClient diagnostics", () => { }); test("reports a hung ACP session/new phase without failing the diagnostic", async () => { - await withFakeACPAgent("hang-session", async (scriptPath, mode) => { + await withFakeACPAgent("hang-session", async (scriptPath, mode, testDir) => { + const tracePath = path.join(testDir, "phase-trace.jsonl"); const client = new GenericACPAgentClient({ logger: createTestLogger(), - command: [process.execPath, scriptPath, mode], + command: [process.execPath, scriptPath, mode, "", tracePath], providerId: "grok", label: "Grok", diagnosticPhaseTimeoutMs: TEST_ACP_TIMEOUT_MS, }); - const { diagnostic } = await client.getDiagnostic(); + // Freeze phase deadlines until the child actually reaches session/new. Process startup + // and initialize latency must not consume the session timeout this test exercises. + vi.useFakeTimers({ toFake: ["setTimeout", "clearTimeout"] }); + let diagnostic: string; + try { + const pending = client.getDiagnostic(); + await waitForSessionNew(tracePath); + await vi.advanceTimersByTimeAsync(TEST_ACP_TIMEOUT_MS); + ({ diagnostic } = await pending); + } finally { + vi.useRealTimers(); + } expect(diagnostic).toContain("Grok (ACP)"); expect(diagnostic).toContain("Provider ID: grok"); @@ -356,6 +369,14 @@ async function withTempDir(prefix: string, run: (testDir: string) => Promise { + const readyBy = Date.now() + 10_000; + while (!(await readFile(tracePath, "utf8").catch(() => "")).includes("session/new")) { + if (Date.now() >= readyBy) throw new Error("Fake ACP agent did not reach session/new"); + await delay(20); + } +} + async function expectProcessExit(pid: number): Promise { const deadline = Date.now() + 2_000; while (Date.now() < deadline) { @@ -426,6 +447,7 @@ rl.on("line", (line) => { if (message.method === "session/new") { if (mode === "hang-session") { + if (initializeTracePath) fs.appendFileSync(initializeTracePath, "session/new\\n"); return; }