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>
64 lines
1.8 KiB
TypeScript
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,
|
|
},
|
|
]);
|
|
},
|
|
);
|