mirror of
https://github.com/morluto/rea.git
synced 2026-11-11 01:13:39 +00:00
refactor: remove test-only planning and native UI runtime seams
This commit is contained in:
1 parent
3c4be703cd
commit
fd584d4495
8 files changed
+38
-34
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { expect, it } from "vitest";
|
||||
import { afterEach, expect, it, vi } from "vitest";
|
||||
import * as filesystemSnapshot from "../../process/capture/FilesystemSnapshot.js";
|
||||
|
||||
import { awaitAcknowledgement } from "../../../tests/fixtures/lifecycleAcknowledgement.js";
|
||||
import { createTestTempDirectory } from "../../../tests/fixtures/temporaryDirectory.js";
|
||||
@@ -10,6 +11,8 @@ import { err, ok, type Result } from "../../domain/result.js";
|
||||
import { ProcessCaptureError } from "../../process/capture/ProcessCaptureError.js";
|
||||
import { prepareProcessScenarioPlan } from "./ProcessScenarioPreparation.js";
|
||||
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
|
||||
it("rejects observation roots that capture admission rejects", async () => {
|
||||
const root = await createTestTempDirectory("rea-process-plan-");
|
||||
const file = join(root, "selected");
|
||||
@@ -40,23 +43,24 @@ it("reports cancellation normalized inside admission as planning cancellation",
|
||||
working_directory: ".",
|
||||
});
|
||||
const controller = new AbortController();
|
||||
vi.spyOn(
|
||||
filesystemSnapshot,
|
||||
"admitFilesystemObservationRoots",
|
||||
).mockImplementationOnce(() => {
|
||||
controller.abort("caller stopped during admission");
|
||||
return Promise.resolve(
|
||||
err(
|
||||
new ProcessCaptureError("filesystem observation admission failed", {
|
||||
cause: controller.signal.reason,
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
const prepared = await prepareProcessScenarioPlan(
|
||||
scenario,
|
||||
{},
|
||||
process.platform,
|
||||
controller.signal,
|
||||
{
|
||||
admitRoots: () => {
|
||||
controller.abort("caller stopped during admission");
|
||||
return Promise.resolve(
|
||||
err(
|
||||
new ProcessCaptureError("filesystem observation admission failed", {
|
||||
cause: controller.signal.reason,
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
expect(prepared.ok).toBe(false);
|
||||
@@ -85,18 +89,19 @@ it("reports cancellation after the last awaited admission step", async () => {
|
||||
);
|
||||
let admissionCalls = 0;
|
||||
|
||||
vi.spyOn(
|
||||
filesystemSnapshot,
|
||||
"admitFilesystemObservationRoots",
|
||||
).mockImplementationOnce(() => {
|
||||
admissionCalls += 1;
|
||||
admissionEntered();
|
||||
return pendingAdmission;
|
||||
});
|
||||
const planning = prepareProcessScenarioPlan(
|
||||
scenario,
|
||||
{},
|
||||
process.platform,
|
||||
controller.signal,
|
||||
{
|
||||
admitRoots: () => {
|
||||
admissionCalls += 1;
|
||||
admissionEntered();
|
||||
return pendingAdmission;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Abort only once admission is actually running. Aborting earlier would be
|
||||
|
||||
@@ -14,11 +14,6 @@ import { err, ok, type Result } from "../../domain/result.js";
|
||||
/** A scenario whose executable and observation paths are resolved for execution. */
|
||||
export type ResolvedProcessScenario = Omit<ProcessScenario, "dry_run">;
|
||||
|
||||
/** Test seam for holding the final admission step while cancellation arrives. */
|
||||
export interface ProcessScenarioPreparationHost {
|
||||
readonly admitRoots?: typeof admitFilesystemObservationRoots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a scenario for a dry run. This applies the same executable, working
|
||||
* directory, path and platform admission checks as a capture, then stops
|
||||
@@ -29,7 +24,6 @@ export const prepareProcessScenarioPlan = async (
|
||||
environment: Readonly<Record<string, string | undefined>> = process.env,
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
signal?: AbortSignal,
|
||||
host: ProcessScenarioPreparationHost = {},
|
||||
): Promise<Result<ResolvedProcessScenario, AnalysisError>> => {
|
||||
if (signal?.aborted === true)
|
||||
return err(
|
||||
@@ -60,10 +54,7 @@ export const prepareProcessScenarioPlan = async (
|
||||
if (aborted()) return cancelled();
|
||||
const privacy = createProcessSensitiveOutput(scenario);
|
||||
if (!privacy.ok) return err(privacy.error);
|
||||
const admitted = await (host.admitRoots ?? admitFilesystemObservationRoots)(
|
||||
resolved,
|
||||
signal,
|
||||
);
|
||||
const admitted = await admitFilesystemObservationRoots(resolved, signal);
|
||||
if (!admitted.ok) return aborted() ? cancelled() : admitted;
|
||||
if (aborted()) return cancelled();
|
||||
return ok(resolved);
|
||||
|
||||
@@ -16,8 +16,7 @@ export interface NativeUiHelperRuntime {
|
||||
readonly invoke: NativeUiHelper;
|
||||
readonly cleanupLease: AnalysisCleanupLease;
|
||||
readonly signal: AbortSignal;
|
||||
/** Omitted by test doubles; production runtimes always set the selected deadline. */
|
||||
readonly deadlineMs?: number;
|
||||
readonly deadlineMs: number;
|
||||
close(): Promise<void>;
|
||||
resources(): readonly string[];
|
||||
}
|
||||
|
||||
@@ -374,6 +374,7 @@ describe("native UI deadline execution", () => {
|
||||
environment: {},
|
||||
runtime: {
|
||||
signal: deadline.signal,
|
||||
deadlineMs: 180_000,
|
||||
invoke: async () => ({ ok: true, result: snapshot }),
|
||||
cleanupLease: new AnalysisCleanupLease(async () => undefined),
|
||||
close: async () => undefined,
|
||||
@@ -396,6 +397,7 @@ describe("native UI deadline execution", () => {
|
||||
environment: {},
|
||||
runtime: {
|
||||
signal: deadline.signal,
|
||||
deadlineMs: 180_000,
|
||||
invoke: async () => ({ ok: true, result: snapshot }),
|
||||
cleanupLease: new AnalysisCleanupLease(async () => undefined),
|
||||
close: async () => undefined,
|
||||
@@ -423,6 +425,7 @@ describe("native UI deadline execution", () => {
|
||||
environment: {},
|
||||
runtime: {
|
||||
signal: deadline.signal,
|
||||
deadlineMs: 180_000,
|
||||
invoke: async () => ({ ok: true, result: snapshot }),
|
||||
cleanupLease: new AnalysisCleanupLease(async () => undefined),
|
||||
close: async () => undefined,
|
||||
@@ -493,6 +496,7 @@ describe("native UI interruption provenance", () => {
|
||||
environment: {},
|
||||
runtime: {
|
||||
signal: deadline.signal,
|
||||
deadlineMs: 180_000,
|
||||
invoke: async () => ({ ok: true, result: snapshot }),
|
||||
cleanupLease: new AnalysisCleanupLease(async () => undefined),
|
||||
close: async () => undefined,
|
||||
@@ -531,6 +535,7 @@ describe("native UI interruption provenance", () => {
|
||||
environment: {},
|
||||
runtime: {
|
||||
signal: deadline.signal,
|
||||
deadlineMs: 180_000,
|
||||
invoke: async () => ({ ok: true, result: snapshot }),
|
||||
cleanupLease: new AnalysisCleanupLease(async () => undefined),
|
||||
close: async () => undefined,
|
||||
@@ -552,6 +557,7 @@ describe("native UI interruption provenance", () => {
|
||||
environment: {},
|
||||
runtime: {
|
||||
signal: deadline.signal,
|
||||
deadlineMs: 180_000,
|
||||
invoke: async () => ({ ok: true, result: snapshot }),
|
||||
cleanupLease: new AnalysisCleanupLease(async () => undefined),
|
||||
close: async () => undefined,
|
||||
|
||||
@@ -82,7 +82,7 @@ export const observeNativeUi = async (
|
||||
new NativeUiInterruptionControl(
|
||||
options.signal,
|
||||
runtime.signal,
|
||||
runtime.deadlineMs ?? DEFAULT_NATIVE_UI_DEADLINE_MS,
|
||||
runtime.deadlineMs,
|
||||
);
|
||||
const ownsInterruption = options.interruption === undefined;
|
||||
let result: Result<z.infer<typeof nativeUiResultSchema>, AnalysisError>;
|
||||
|
||||
@@ -32,10 +32,11 @@ const connectNativeUi = async () => {
|
||||
const replies: unknown[] = [];
|
||||
const factory = vi
|
||||
.spyOn(runtimes, "createNativeUiHelperRuntime")
|
||||
.mockImplementation(() => {
|
||||
.mockImplementation((_environment, deadlineMs = 180_000) => {
|
||||
const cleanupLease = new AnalysisCleanupLease(async () => {});
|
||||
return {
|
||||
signal: new AbortController().signal,
|
||||
deadlineMs,
|
||||
cleanupLease,
|
||||
invoke: async () => {
|
||||
if (replies.length === 0)
|
||||
|
||||
@@ -42,6 +42,7 @@ it.each([false, true])(
|
||||
});
|
||||
const runtime = {
|
||||
signal: deadline.signal,
|
||||
deadlineMs: 180_000,
|
||||
cleanupLease,
|
||||
invoke: async () => ({ ok: true, result: snapshot }),
|
||||
close: () => cleanupLease.release(),
|
||||
|
||||
@@ -39,6 +39,7 @@ const controlledRuntime = (
|
||||
return {
|
||||
cleanupLease,
|
||||
signal,
|
||||
deadlineMs: 180_000,
|
||||
invoke: vi.fn(async () => ({ ok: true, result: snapshot })),
|
||||
close: vi.fn(() => cleanupLease.release()),
|
||||
resources: () => (cleanupLease.released ? [] : ["controlled-ui-runtime"]),
|
||||
|
||||
Reference in new issue
Block a user