Files
rea/tests/boundary/providers/hopper/hopperBridgeReconnect.test.ts
T
069308bbe6 fix(hopper): preserve startup failures and recover denied launches
Preserve the primary Hopper startup failure and launcher diagnostics while retaining resources when cleanup cannot be confirmed. Reauthenticate matching external application sessions before document cleanup, keep the Python bridge available for bounded reconnects, and expose the provider-owned Hopper startup deadline.

Real headless Linux Hopper semantic analysis and 65 focused configuration, handshake, cleanup, and bridge tests passed. macOS authorization/crash causes and saved-HOP behavior require their own real-provider verification.

Refs #1808

Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
2026-10-11 22:35:01 +08:00

64 lines
1.8 KiB
TypeScript

import { execFile } from "node:child_process";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
import { expect, it, onTestFinished } from "vitest";
import { z } from "zod";
import { PrivateRuntimeRoot } from "../../../../src/process/PrivateRuntimeRoot.js";
const execute = promisify(execFile);
it.skipIf(process.platform === "win32")(
"the shipped bridge reauthenticates reconnects and releases its execution thread after expiry",
async () => {
const runtime = await PrivateRuntimeRoot.create({ parent: "/tmp" });
onTestFinished(() => runtime.close());
const { stdout } = await execute("python3", [
fileURLToPath(
new URL(
"../../../fixtures/hopperBridgeReconnectProbe.py",
import.meta.url,
),
),
fileURLToPath(
new URL("../../../../bridge/hopper_bridge.py", import.meta.url),
),
runtime.path,
]);
const rows = z
.array(
z.object({
mode: z.string(),
requests: z.array(z.string()),
listener_removed: z.literal(true),
thread_released: z.literal(true),
}),
)
.parse(JSON.parse(stdout));
expect(rows).toEqual([
{
mode: "unauthorized",
requests: ["health", "shutdown_document", "shutdown_document"],
listener_removed: true,
thread_released: true,
},
...["disconnect", "lost-reply"].map((mode) => ({
mode,
requests: [
"health",
"health",
"shutdown_document",
"shutdown_document",
],
listener_removed: true,
thread_released: true,
})),
{
mode: "expiry",
requests: ["health"],
listener_removed: true,
thread_released: true,
},
]);
},
);