Files
rea/tests/boundary/providers/hopper/hopperRegexFailure.test.ts
T
morluto 5853089885 fix(hopper): retain search failure context and cleanup ownership
Attribute regex inventory failures to the accepted search operation while retaining wire identity, typed outcomes, captured facts and live cleanup dependencies. Preserve exact cancellation reasons at inventory and progress completion.

Validated with focused source, socket-boundary and public CLI fixtures, existing MCP contract checks, check:fast and docs:check. Simulated Hopper only; real-engine behavior and performance costs remain unmeasured. Refs #4680.
2026-10-17 13:12:43 +08:00

98 lines
3.3 KiB
TypeScript

import { expect, it } from "vitest";
import { HopperRegexSearch } from "../../../../src/hopper/HopperRegexSearch.js";
import { HopperRemoteError } from "../../../../src/domain/hopperErrors.js";
import { projectAnalysisError } from "../../../../src/domain/analysisErrorProjection.js";
import {
HopperFixtureLauncher,
startHopperFixtureClient,
} from "./hopperClient.fixture.js";
it.each(
(["search_strings", "search_procedures"] as const).flatMap((operation) =>
(["capability_unavailable", "bridge_exception"] as const).map(
(failure) => ({ operation, failure }),
),
),
)(
"attributes real bridge $failure inventory response to $operation and preserves wire identity",
async ({ operation, failure }) => {
const launcher = new HopperFixtureLauncher(
undefined,
"quiet",
"ready",
"acknowledge",
failure,
);
const client = await startHopperFixtureClient(launcher);
const search = new HopperRegexSearch(client);
try {
const result = await search.execute(operation, {
mode: "regex",
pattern: "fixture",
case_sensitive: false,
document: "selected-document",
});
if (result.ok) throw new Error("Expected fixture failure");
const inventory =
operation === "search_strings" ? "list_strings" : "list_procedures";
const request = await launcher.waitForRequest(inventory);
expect(request.params).toEqual({ document: "selected-document" });
const projected = projectAnalysisError(result.error);
expect(projected.code).toBe(
failure === "capability_unavailable"
? "capability_unavailable"
: "execution_failure",
);
expect(projected.details?.operation).toBe(operation);
expect(result.error.diagnostics).toMatchObject({
provider_request: {
operation: inventory,
request_id: request.id,
provider_code: -32000,
diagnostic_type: failure,
},
});
if (failure !== "capability_unavailable") {
expect(projected.message).toContain(operation);
expect(result.error.cause).toBeInstanceOf(HopperRemoteError);
expect(result.error.cause).toMatchObject({
operation: inventory,
requestId: request.id,
});
}
} finally {
await search.close();
expect((await client.close()).ok).toBe(true);
}
},
);
it.each(["search_strings", "search_procedures"] as const)(
"preserves successful %s search and caller-selected document",
async (operation) => {
const launcher = new HopperFixtureLauncher();
const client = await startHopperFixtureClient(launcher);
const search = new HopperRegexSearch(client);
try {
expect(
await search.execute(operation, {
mode: "regex",
pattern: "fixture",
case_sensitive: false,
document: "selected-document",
}),
).toMatchObject({
ok: true,
value: [{ address: "0x1000", value: "fixture" }],
});
const request = await launcher.waitForRequest(
operation === "search_strings" ? "list_strings" : "list_procedures",
);
expect(request.params).toEqual({ document: "selected-document" });
} finally {
await search.close();
expect((await client.close()).ok).toBe(true);
}
},
);