test(kuna): distinguish prelaunch expiry from captured command output

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
N0zoM1z0andgensokyo-dev authored and gensokyo-dev committed 2026-11-11 21:19:01 +08:00
1 parent 04042cf540
commit 4a17bf76ed
2 files changed
+77 -5

No files matched your search

@@ -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<never>((_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<typeof commands.run> | 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);
}
},
);
@@ -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",