From 4a17bf76ed90717c15cd3955ff8138a52dfe341f Mon Sep 17 00:00:00 2001 From: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com> Date: Wed, 11 Nov 2026 12:42:13 +0000 Subject: [PATCH] test(kuna): distinguish prelaunch expiry from captured command output Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com> --- .../kuna/kunaCommandFailures.test.ts | 75 ++++++++++++++++++- .../providers/kuna/kunaProvider.test.ts | 7 +- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/tests/boundary/providers/kuna/kunaCommandFailures.test.ts b/tests/boundary/providers/kuna/kunaCommandFailures.test.ts index acf89ebe74..f61697c8d8 100644 --- a/tests/boundary/providers/kuna/kunaCommandFailures.test.ts +++ b/tests/boundary/providers/kuna/kunaCommandFailures.test.ts @@ -1,10 +1,11 @@ import { expect, it as test, vi } from "vitest"; +import type { KunaProcessLauncher } from "../../../../src/kuna/KunaCommand.js"; import { projectAnalysisError } from "../../../../src/domain/analysisErrorProjection.js"; import { inspectKunaInstallationOwned as inspectKunaInstallation } from "./kunaResourceScope.js"; import { KunaTargetCommands } from "../../../../src/kuna/KunaTargetCommands.js"; import { fakeKunaCalls } from "./fakeKuna.js"; -import { session } from "./kunaSessionFixture.js"; +import { session, awaitKunaCommand } from "./kunaSessionFixture.js"; const it = test.skipIf(process.platform === "win32"); @@ -248,3 +249,75 @@ it("does not invent a caller cause when closed without cancellation", async () = expect(await fakeKunaCalls(kuna)).toEqual(callsBefore); expect(await commands.close()).toEqual({ ok: true, value: null }); }); + +it.each(["before-launch", "after-launch"] as const)( + "keeps timeout output coverage truthful when expiry is %s", + async (phase) => { + const fixture = await session("rea-kuna-timeout-output-", { + inventory: "hang", + }); + const installed = await inspectKunaInstallation({ + REA_KUNA_COMMAND: fixture.kuna, + REA_KUNA_CACHE_DIR: fixture.cacheRoot, + }); + if (!installed.ok) throw new Error(installed.error.reason); + const controller = new AbortController(); + const waitForDeadline: KunaProcessLauncher = async (options) => + new Promise((_resolve, reject) => { + const signal = options.signal; + if (signal === undefined) + throw new Error("Missing command deadline signal"); + if (signal.aborted) reject(signal.reason); + else + signal.addEventListener("abort", () => reject(signal.reason), { + once: true, + }); + }); + const commands = new KunaTargetCommands(fixture.target, { + signal: controller.signal, + ...(phase === "before-launch" ? { launcher: waitForDeadline } : {}), + }); + let pending: ReturnType | undefined; + try { + expect((await commands.prepare()).ok).toBe(true); + pending = commands.run({ + installation: installed.value, + operation: "list_procedures", + arguments: (input) => ["functions", input, "--json"], + deadline: { + setting: "REA_KUNA_TIMEOUT_MS", + source: "setting", + ms: 1000, + }, + outputBytes: 16384, + signal: controller.signal, + }); + if (phase === "after-launch") + await awaitKunaCommand(fixture.kuna, "functions", pending); + const result = await pending; + if (result.ok) throw new Error("Expected a command timeout"); + const projected = projectAnalysisError(result.error); + expect(projected).toMatchObject({ + code: "provider_timeout", + details: { timeout_ms: 1000 }, + }); + const calls = (await fakeKunaCalls(fixture.kuna)).filter( + ({ argv }) => argv[0] === "functions", + ); + expect(calls).toHaveLength(phase === "after-launch" ? 1 : 0); + if (phase === "after-launch") { + expect(projected.details).toMatchObject({ + captured_output: { stdout: "", stderr: "", truncated: false }, + }); + } else { + expect(result.error.capturedOutput).toBeUndefined(); + expect(projected.details).not.toHaveProperty("captured_output"); + } + } finally { + controller.abort(); + await commands.close(); + await pending; + expect((await commands.close()).ok).toBe(true); + } + }, +); diff --git a/tests/boundary/providers/kuna/kunaProvider.test.ts b/tests/boundary/providers/kuna/kunaProvider.test.ts index 52d82ee3ce..44f206bca2 100644 --- a/tests/boundary/providers/kuna/kunaProvider.test.ts +++ b/tests/boundary/providers/kuna/kunaProvider.test.ts @@ -1179,10 +1179,9 @@ it.each([ environment: { REA_KUNA_PROJECT_TIMEOUT_MS: "300" }, cause: "AnalysisTimeoutError", next: "To retry, set kuna.project_timeout_ms above 300 ms with update_analysis_settings. It can be changed at runtime. The launch seed is REA_KUNA_PROJECT_TIMEOUT_MS. Then reopen the target so the export runs again.", - details: { - timeout_ms: 300, - captured_output: { truncated: expect.any(Boolean) }, - }, + // The whole export can expire during preparation, before a child exists. + // Command-output presence is covered at the command owner below that boundary. + details: { timeout_ms: 300 }, }, { name: "Kuna failure",