fix(runtime): retain Inspector and Electron cleanup ownership
This commit is contained in:
1 parent
7f4e7d5577
commit
87ab054ea3
23 files changed
+1901
-321
No files matched your search
@@ -205,3 +205,42 @@ it("retains completed target facts when cancellation arrives before Evidence pub
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it.each(["list", "inspect"] as const)(
|
||||
"preserves a pre-abort reason before Electron %s provider work",
|
||||
async (kind) => {
|
||||
const reason = new Error(`stop Electron ${kind}`);
|
||||
const controller = new AbortController();
|
||||
controller.abort(reason);
|
||||
let providerCalls = 0;
|
||||
const provider: ElectronObservationPort = {
|
||||
identity: () => identity,
|
||||
listTargets: async () => {
|
||||
providerCalls += 1;
|
||||
return err(new AnalysisCancelledError("list_electron_targets"));
|
||||
},
|
||||
inspectPage: async () => {
|
||||
providerCalls += 1;
|
||||
return err(new AnalysisCancelledError("inspect_electron_page"));
|
||||
},
|
||||
};
|
||||
|
||||
const result =
|
||||
kind === "list"
|
||||
? await listElectronTargets(
|
||||
provider,
|
||||
{ cdp_endpoint: input.cdp_endpoint },
|
||||
{ signal: controller.signal },
|
||||
)
|
||||
: await inspectElectronPage(provider, input, {
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (!result.ok) {
|
||||
expect(result.error).toBeInstanceOf(AnalysisCancelledError);
|
||||
expect(result.error.cause).toBe(reason);
|
||||
}
|
||||
expect(providerCalls).toBe(0);
|
||||
},
|
||||
);
|
||||
@@ -29,7 +29,11 @@ export const listElectronTargets = async (
|
||||
const ready = requireProvider(provider, "list_electron_targets");
|
||||
if (!ready.ok) return ready;
|
||||
if (options.signal?.aborted)
|
||||
return err(new AnalysisCancelledError("list_electron_targets"));
|
||||
return err(
|
||||
new AnalysisCancelledError("list_electron_targets", {
|
||||
cause: options.signal.reason,
|
||||
}),
|
||||
);
|
||||
const result = await ready.value.listTargets(input, options);
|
||||
if (!result.ok) return result;
|
||||
const report = electronTargetListSchema.safeParse(result.value);
|
||||
@@ -61,7 +65,11 @@ export const inspectElectronPage = async (
|
||||
const ready = requireProvider(provider, "inspect_electron_page");
|
||||
if (!ready.ok) return ready;
|
||||
if (options.signal?.aborted)
|
||||
return err(new AnalysisCancelledError("inspect_electron_page"));
|
||||
return err(
|
||||
new AnalysisCancelledError("inspect_electron_page", {
|
||||
cause: options.signal.reason,
|
||||
}),
|
||||
);
|
||||
const result = await ready.value.inspectPage(input, options);
|
||||
if (!result.ok) {
|
||||
const partial = result.error.partialObservation;
|
||||
|
||||
@@ -13,6 +13,8 @@ import type { Result } from "../../domain/result.js";
|
||||
|
||||
/** Provider-neutral boundary for passive Node/Electron Inspector observation. */
|
||||
export interface JavaScriptRuntimeObservationPort {
|
||||
/** Retry retained Inspector and associated file cleanup during shutdown. */
|
||||
close?(): Promise<void>;
|
||||
identity(): ProviderIdentity;
|
||||
listTargets(
|
||||
input: ListJavaScriptRuntimeTargetsInput,
|
||||
|
||||
@@ -271,3 +271,49 @@ it("reports non-JSON Inspector output before late cancellation", async () => {
|
||||
error: { _tag: "AnalysisOutputError", partialObservation: undefined },
|
||||
});
|
||||
});
|
||||
|
||||
it.each(["list", "observe"] as const)(
|
||||
"preserves a pre-abort reason before Inspector %s provider work",
|
||||
async (kind) => {
|
||||
const reason = new Error(`stop Inspector ${kind}`);
|
||||
const controller = new AbortController();
|
||||
controller.abort(reason);
|
||||
let providerCalls = 0;
|
||||
const provider: JavaScriptRuntimeObservationPort = {
|
||||
identity: () => ({ id: "test", name: "Test", version: "1" }),
|
||||
listTargets: async () => {
|
||||
providerCalls += 1;
|
||||
return err(
|
||||
new AnalysisCancelledError("list_javascript_runtime_targets"),
|
||||
);
|
||||
},
|
||||
observe: async () => {
|
||||
providerCalls += 1;
|
||||
return err(new AnalysisCancelledError("observe_javascript_runtime"));
|
||||
},
|
||||
};
|
||||
const result =
|
||||
kind === "list"
|
||||
? await listJavaScriptRuntimeTargets(
|
||||
provider,
|
||||
{ inspector_endpoint: "http://127.0.0.1:9229" },
|
||||
{ signal: controller.signal },
|
||||
)
|
||||
: await observeJavaScriptRuntime(
|
||||
provider,
|
||||
{
|
||||
inspector_endpoint: "http://127.0.0.1:9229",
|
||||
target_id: "target",
|
||||
observation_ms: 0,
|
||||
},
|
||||
{ signal: controller.signal },
|
||||
);
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
if (!result.ok) {
|
||||
expect(result.error).toBeInstanceOf(AnalysisCancelledError);
|
||||
expect(result.error.cause).toBe(reason);
|
||||
}
|
||||
expect(providerCalls).toBe(0);
|
||||
},
|
||||
);
|
||||
@@ -28,7 +28,11 @@ export const listJavaScriptRuntimeTargets = async (
|
||||
const ready = requireProvider(provider, "list_javascript_runtime_targets");
|
||||
if (!ready.ok) return ready;
|
||||
if (options.signal?.aborted)
|
||||
return err(new AnalysisCancelledError("list_javascript_runtime_targets"));
|
||||
return err(
|
||||
new AnalysisCancelledError("list_javascript_runtime_targets", {
|
||||
cause: options.signal.reason,
|
||||
}),
|
||||
);
|
||||
const result = await ready.value.listTargets(input, options);
|
||||
if (!result.ok) return result;
|
||||
const report = javascriptRuntimeTargetListSchema.safeParse(result.value);
|
||||
@@ -58,7 +62,11 @@ export const observeJavaScriptRuntime = async (
|
||||
const ready = requireProvider(provider, "observe_javascript_runtime");
|
||||
if (!ready.ok) return ready;
|
||||
if (options.signal?.aborted)
|
||||
return err(new AnalysisCancelledError("observe_javascript_runtime"));
|
||||
return err(
|
||||
new AnalysisCancelledError("observe_javascript_runtime", {
|
||||
cause: options.signal.reason,
|
||||
}),
|
||||
);
|
||||
const result = await ready.value.observe(input, options);
|
||||
if (!result.ok) {
|
||||
const partial = result.error.partialObservation;
|
||||
|
||||
Reference in new issue
Block a user