mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
146 lines
4.9 KiB
TypeScript
146 lines
4.9 KiB
TypeScript
import {
|
|
mkdir,
|
|
readFile,
|
|
readdir,
|
|
realpath,
|
|
writeFile,
|
|
} from "node:fs/promises";
|
|
import { dirname, join } from "node:path";
|
|
import { expect, it, onTestFinished, vi } from "vitest";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
|
|
const failure = vi.hoisted(() => ({
|
|
parent: undefined as string | undefined,
|
|
kind: undefined as "directory" | "content" | "destination" | undefined,
|
|
}));
|
|
vi.mock("node:fs/promises", async (importOriginal) => {
|
|
const filesystem = await importOriginal<typeof import("node:fs/promises")>();
|
|
const { dirname } = await import("node:path");
|
|
const pathFailure = () =>
|
|
Object.assign(new Error("controlled filesystem pathname ceiling"), {
|
|
code: "ENAMETOOLONG",
|
|
});
|
|
return {
|
|
...filesystem,
|
|
mkdtemp: async (...args: Parameters<typeof filesystem.mkdtemp>) => {
|
|
if (
|
|
failure.kind === "directory" &&
|
|
dirname(String(args[0])) === failure.parent
|
|
)
|
|
throw pathFailure();
|
|
return filesystem.mkdtemp(...args);
|
|
},
|
|
open: async (...args: Parameters<typeof filesystem.open>) => {
|
|
if (
|
|
failure.kind === "content" &&
|
|
dirname(dirname(String(args[0]))) === failure.parent
|
|
)
|
|
throw pathFailure();
|
|
return filesystem.open(...args);
|
|
},
|
|
realpath: async (...args: Parameters<typeof filesystem.realpath>) => {
|
|
if (failure.kind === "destination" && String(args[0]) === failure.parent)
|
|
throw pathFailure();
|
|
return filesystem.realpath(...args);
|
|
},
|
|
};
|
|
});
|
|
import { ArtifactResourceScope } from "../../../src/artifacts/ArtifactResourceScope.js";
|
|
import { writeTextParts } from "../../../src/application/JsonFiles.js";
|
|
import { projectAnalysisError } from "../../../src/domain/analysisErrorProjection.js";
|
|
|
|
it.each(["directory", "content"] as const)(
|
|
"falls back to a shorter same-filesystem staging parent after %s pathname exhaustion and removes every stage",
|
|
async (kind) => {
|
|
const root = await createTestTempDirectory("rea-staging-path-capacity-");
|
|
const parent = join(root, "nested");
|
|
await mkdir(parent);
|
|
const resources = new ArtifactResourceScope();
|
|
onTestFinished(() => resources.close());
|
|
failure.parent = await realpath(parent);
|
|
failure.kind = kind;
|
|
try {
|
|
const destination = join(parent, "out.json");
|
|
const result = await writeTextParts(
|
|
["exact", " bytes"],
|
|
destination,
|
|
false,
|
|
resources,
|
|
);
|
|
expect(result).toMatchObject({
|
|
ok: true,
|
|
value: { path: destination, bytes: 11 },
|
|
});
|
|
expect(await readFile(destination, "utf8")).toBe("exact bytes");
|
|
expect(await readdir(parent)).toEqual(["out.json"]);
|
|
expect(await readdir(root)).toEqual(["nested"]);
|
|
} finally {
|
|
failure.kind = undefined;
|
|
failure.parent = undefined;
|
|
}
|
|
},
|
|
);
|
|
|
|
it("reports an actual selected-parent pathname refusal as a filesystem resource constraint", async () => {
|
|
const root = await createTestTempDirectory("rea-selected-path-capacity-");
|
|
const resources = new ArtifactResourceScope();
|
|
onTestFinished(() => resources.close());
|
|
failure.parent = root;
|
|
failure.kind = "destination";
|
|
try {
|
|
const result = await writeTextParts(
|
|
["bytes"],
|
|
join(root, "out.json"),
|
|
false,
|
|
resources,
|
|
);
|
|
expect(result.ok).toBe(false);
|
|
if (!result.ok)
|
|
expect(projectAnalysisError(result.error)).toMatchObject({
|
|
code: "resource_constraint",
|
|
category: "resource_constraint",
|
|
retryable: false,
|
|
details: { reason: "path-limit", boundary: "filesystem-path" },
|
|
});
|
|
expect(await readdir(root)).toEqual([]);
|
|
} finally {
|
|
failure.kind = undefined;
|
|
failure.parent = undefined;
|
|
}
|
|
});
|
|
|
|
it.skipIf(process.platform !== "darwin")(
|
|
"publishes under a real macOS parent near the pathname limit when direct destination creation is supported",
|
|
async () => {
|
|
const root = await realpath(
|
|
await createTestTempDirectory("rea-long-parent-"),
|
|
);
|
|
let parent = root;
|
|
while (Buffer.byteLength(parent) + 201 < 1002) {
|
|
parent = join(parent, "b".repeat(200));
|
|
await mkdir(parent);
|
|
}
|
|
const remaining = 1002 - Buffer.byteLength(parent) - 1;
|
|
if (remaining > 0) {
|
|
parent = join(parent, "l".repeat(remaining));
|
|
await mkdir(parent);
|
|
}
|
|
const bytes = "canonical output bytes";
|
|
await writeFile(join(parent, "out.json.probe"), bytes);
|
|
const resources = new ArtifactResourceScope();
|
|
onTestFinished(() => resources.close());
|
|
const destination = join(parent, "out.json");
|
|
const result = await writeTextParts([bytes], destination, false, resources);
|
|
expect(result.ok).toBe(true);
|
|
expect(await readFile(destination, "utf8")).toBe(bytes);
|
|
expect(
|
|
(await readdir(parent)).filter((name) => name.startsWith(".rea-write-")),
|
|
).toEqual([]);
|
|
expect(
|
|
(await readdir(dirname(parent))).filter((name) =>
|
|
name.startsWith(".rea-write-"),
|
|
),
|
|
).toEqual([]);
|
|
},
|
|
);
|