Files
rea/tests/boundary/filesystem/jsonFileResourceOwnership.test.ts
morluto d8c76b6296 fix(io): retain cleanup ownership and honor cancellation
Keep failed JSON read handles in the existing server resource scope and fail admission until cleanup succeeds. Thread cancellation through every process CLI input read and replace timer-driven cancellation checks with a shared first-read gate.

Classify authenticated standalone Evidence as wrong-kind input while preserving tampered-record integrity failures and actionable messages across ledger, CLI, and MCP consumers. Record unrelated CS_RESTRICT process neighbors as unverified without weakening related-process ownership checks. Update stale ADB fixtures for the actual shell protocol.

Validated focused CLI, MCP, filesystem, ownership, and error projection tests; static, docs, and duplication gates pass. The host-level CS_RESTRICT load reproduction was not run. Refs #2050, #2035, #2064.
2026-10-12 14:12:44 +08:00

76 lines
2.9 KiB
TypeScript

import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it, vi } from "vitest";
import { ArtifactResourceScope } from "../../../src/artifacts/ArtifactResourceScope.js";
import { readJsonFile } from "../../../src/application/JsonFiles.js";
import { RegularFileCleanupFailure } from "../../../src/application/RegularFileRead.js";
import { OwnedFileHandle } from "../../../src/filesystem/OwnedFileHandle.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
it("retains and retries a JSON file owner after a persistent close failure", async () => {
const root = await createTestTempDirectory("rea-json-file-owner-");
const path = join(root, "input.json");
await writeFile(path, '{"value":"retained"}');
const resources = new ArtifactResourceScope();
const closeFailure = new Error("injected persistent close failure");
let attempts = 0;
const close = vi
.spyOn(OwnedFileHandle.prototype, "close")
.mockImplementation(async () => {
attempts += 1;
throw closeFailure;
});
let failure: unknown;
try {
try {
await readJsonFile(path, undefined, resources);
} catch (cause: unknown) {
failure = cause;
}
expect(failure).toBeInstanceOf(RegularFileCleanupFailure);
if (!(failure instanceof RegularFileCleanupFailure))
throw new Error("Expected the failed file owner to remain visible");
expect(failure.cleanupCause).toBe(closeFailure);
expect(failure.outcome).toMatchObject({
kind: "completed",
value: { ok: true, value: { value: "retained" } },
});
expect(failure.owner.handle.fd).toBeGreaterThanOrEqual(0);
expect(attempts).toBe(2);
} finally {
close.mockRestore();
await resources.close();
}
if (!(failure instanceof RegularFileCleanupFailure))
throw new Error("Expected the retained file owner");
expect(failure.owner.handle.fd).toBe(-1);
});
it("returns parsed JSON when a failed file close is recovered by the resource scope", async () => {
const root = await createTestTempDirectory("rea-json-file-close-retry-");
const path = join(root, "input.json");
await writeFile(path, '{"value":"retained"}');
const resources = new ArtifactResourceScope();
const closeFailure = new Error("injected transient close failure");
const originalClose = OwnedFileHandle.prototype.close;
let attempts = 0;
const close = vi
.spyOn(OwnedFileHandle.prototype, "close")
.mockImplementation(async function (this: OwnedFileHandle) {
attempts += 1;
if (attempts === 1) throw closeFailure;
await originalClose.call(this);
});
try {
const parsed = await readJsonFile(path, undefined, resources);
if (!parsed.ok) throw parsed.error;
expect(parsed.value).toEqual({ value: "retained" });
expect(attempts).toBe(2);
} finally {
close.mockRestore();
await resources.close();
}
});