test(hopper): align startup fixtures with cleanup and lease contracts
Inspect the typed primary startup failure retained by aggregate cleanup errors. Materialize isolated targets before real lease acquisition so launcher scenarios reach the behavior under test. Repairs the Linux shard and Windows curated test failures without weakening cleanup retention coverage.
This commit is contained in:
parent
d4e8ef7499
commit
b3dec005bc
|
|
@ -165,10 +165,12 @@ describe("Hopper bridge launcher selection", () => {
|
|||
|
||||
it("launches Hopper helpers with the caller-selected environment without restoring ambient values", async () => {
|
||||
const directory = await createTestTempDirectory("rea-hopper-selected-env-");
|
||||
const targetPath = join(directory, "target");
|
||||
await writeFile(targetPath, "fixture target");
|
||||
const launcher = new HopperApplicationLauncher({
|
||||
environment: { REA_SELECTED_VALUE: "caller-value" },
|
||||
launcherPath: process.execPath,
|
||||
targetPath: join(directory, "target"),
|
||||
targetPath,
|
||||
targetKind: "executable",
|
||||
loaderArgs: [
|
||||
"-e",
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ const failedStartup = async (launcher: RetryCleanupLauncher) => {
|
|||
error: {
|
||||
_tag: "ProviderAdapterError",
|
||||
cleanupIncomplete: true,
|
||||
cause: { _tag: "HopperTimeoutError" },
|
||||
cause: { cause: { _tag: "HopperTimeoutError" } },
|
||||
},
|
||||
});
|
||||
const session = launcher.sessions[0];
|
||||
|
|
@ -233,7 +233,7 @@ it("blocks a fresh launch while cleanup remains unverified", async () => {
|
|||
ok: false,
|
||||
error: {
|
||||
cleanupIncomplete: true,
|
||||
cause: { _tag: "HopperTimeoutError" },
|
||||
cause: { cause: { _tag: "HopperTimeoutError" } },
|
||||
diagnostics: { primary_error: { code: "provider_timeout" } },
|
||||
},
|
||||
});
|
||||
|
|
@ -263,7 +263,7 @@ it("preserves failed startup state through a blocked retry until cleanup succeed
|
|||
error: {
|
||||
_tag: "ProviderAdapterError",
|
||||
cleanupIncomplete: true,
|
||||
cause: { _tag: "HopperTimeoutError" },
|
||||
cause: { cause: { _tag: "HopperTimeoutError" } },
|
||||
},
|
||||
});
|
||||
// ...but must not wipe the failed-startup state: the client still
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import { spawn } from "node:child_process";
|
||||
import { access } from "node:fs/promises";
|
||||
import { access, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { expect, it, onTestFinished } from "vitest";
|
||||
|
||||
import { createTestTempDirectory } from "../../../fixtures/temporaryDirectory.js";
|
||||
|
||||
import { AnalysisError } from "../../../../src/domain/analysisErrorBase.js";
|
||||
import { projectAnalysisError } from "../../../../src/domain/analysisErrorProjection.js";
|
||||
import { ok } from "../../../../src/domain/result.js";
|
||||
|
|
@ -67,17 +70,23 @@ const trackFailedHelperClient = (
|
|||
const projectPrimaryStartupFailure = (error: AnalysisError) => {
|
||||
if (!error.cleanupIncomplete) return projectAnalysisError(error);
|
||||
expect(projectAnalysisError(error).code).toBe("cleanup_incomplete");
|
||||
const primary = error.cause;
|
||||
const cause = error.cause;
|
||||
if (!(cause instanceof AggregateError))
|
||||
throw new Error("Cleanup failure did not retain its aggregate causes");
|
||||
const primary = cause.cause;
|
||||
if (!(primary instanceof AnalysisError))
|
||||
throw new Error("Cleanup failure lost its typed startup cause");
|
||||
return projectAnalysisError(primary);
|
||||
};
|
||||
|
||||
it("does not equate an owned native helper exit with an external GUI exit", async () => {
|
||||
const directory = await createTestTempDirectory("rea-hopper-helper-failure-");
|
||||
const targetPath = join(directory, "target");
|
||||
await writeFile(targetPath, "fixture target");
|
||||
const launcher = new HopperApplicationLauncher({
|
||||
environment: {},
|
||||
launcherPath: process.execPath,
|
||||
targetPath: "/target",
|
||||
targetPath,
|
||||
targetKind: "executable",
|
||||
loaderArgs: [
|
||||
"-e",
|
||||
|
|
@ -91,7 +100,10 @@ it("does not equate an owned native helper exit with an external GUI exit", asyn
|
|||
const result = await client.start();
|
||||
expect(result).toMatchObject({
|
||||
ok: false,
|
||||
error: { cleanupIncomplete: true, cause: { _tag: "HopperStartError" } },
|
||||
error: {
|
||||
cleanupIncomplete: true,
|
||||
cause: { cause: { _tag: "HopperStartError" } },
|
||||
},
|
||||
});
|
||||
if (result.ok) throw new Error("Expected the native helper to fail");
|
||||
expect(projectPrimaryStartupFailure(result.error)).toMatchObject({
|
||||
|
|
@ -140,7 +152,10 @@ it.each(["exit", "signal", "exit75"] as const)(
|
|||
const result = await client.start();
|
||||
expect(result).toMatchObject({
|
||||
ok: false,
|
||||
error: { cleanupIncomplete: true, cause: { _tag: "HopperStartError" } },
|
||||
error: {
|
||||
cleanupIncomplete: true,
|
||||
cause: { cause: { _tag: "HopperStartError" } },
|
||||
},
|
||||
});
|
||||
if (result.ok) throw new Error("Expected the launcher to fail");
|
||||
const projected = projectPrimaryStartupFailure(result.error);
|
||||
|
|
|
|||
Loading…
Reference in New Issue