mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
c324d31b45
Remove shared-module mocks for input reads, heap statistics, and tarball streaming. Exercise actual file changes and real V8 heap admission in fresh CLI processes; keep only selected-descriptor syscall fault injection for the pathless EIO case. Reproduced the four hosted source failures with a preloaded module graph and found the same flaw in the adjacent tarball test. The preloaded control now passes 17 cases; 32 focused tests, all 1,739 service tests (2 skips), and check:ci pass. Snapshot, cleanup, identity, and error projection coverage is retained.
194 lines
6.7 KiB
TypeScript
194 lines
6.7 KiB
TypeScript
import {
|
|
appendFile,
|
|
readFile,
|
|
stat,
|
|
truncate,
|
|
writeFile,
|
|
} from "node:fs/promises";
|
|
import { join, resolve } from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
|
|
import { expect } from "vitest";
|
|
import { z } from "zod";
|
|
|
|
import { nativeJsonParseRequiredBytes } from "../../../src/application/JsonInputFile.js";
|
|
import { writeEnvironmentServeFiles } from "../../fixtures/environmentServe.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
|
|
const probe = pathToFileURL(
|
|
resolve("tests/fixtures/environmentExportInputProbe.mjs"),
|
|
).href;
|
|
|
|
for (const role of ["manifest", "evidence"] as const) {
|
|
cliTest(
|
|
`refuses a real ${role} file changed during its read`,
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-export-input-race-cli-");
|
|
const files = await writeEnvironmentServeFiles(root);
|
|
const input =
|
|
role === "manifest" ? files.manifestPath : files.capturePath;
|
|
const before = await readFile(input);
|
|
const marker = join(root, "read-marker");
|
|
const directory = join(root, "bundle");
|
|
const result = await cli.run({
|
|
arguments: [
|
|
"environment-export",
|
|
files.manifestPath,
|
|
"--evidence",
|
|
files.capturePath,
|
|
directory,
|
|
"--json",
|
|
],
|
|
environment: {
|
|
NODE_OPTIONS: `--import=${probe} --max-old-space-size=256`,
|
|
REA_TEST_EXPORT_INPUT: input,
|
|
REA_TEST_EXPORT_READ_MARKER: marker,
|
|
REA_TEST_EXPORT_READ_ACTION: "append",
|
|
},
|
|
timeoutMs: 30_000,
|
|
});
|
|
expect(await readFile(marker, "utf8")).toBe("read");
|
|
expect(await readFile(input)).toEqual(
|
|
Buffer.concat([before, Buffer.from(" ")]),
|
|
);
|
|
expect(result.exitCode, result.stderr).toBe(1);
|
|
expect(result.json).toMatchObject({
|
|
code: "invalid_request",
|
|
details: {
|
|
operation: "environment-export",
|
|
issues: [{ path: [role], reason: "invalid_value" }],
|
|
},
|
|
});
|
|
await expect(stat(directory)).rejects.toMatchObject({ code: "ENOENT" });
|
|
},
|
|
);
|
|
}
|
|
|
|
const heapRefusalSchema = z.object({
|
|
code: z.literal("resource_constraint"),
|
|
details: z.object({
|
|
operation: z.literal("environment-export"),
|
|
resource: z.literal("memory"),
|
|
reported_limits: z.object({
|
|
input_path: z.string(),
|
|
input_file_bytes: z.number(),
|
|
required_heap_bytes: z.number(),
|
|
available_heap_bytes: z.number(),
|
|
}),
|
|
}),
|
|
});
|
|
|
|
cliTest(
|
|
"admits neither the whole read nor an unbudgeted snapshot under a real heap limit",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-export-input-heap-cli-");
|
|
const files = await writeEnvironmentServeFiles(root);
|
|
const originalBytes = (await stat(files.manifestPath)).size;
|
|
const marker = join(root, "read-marker");
|
|
const directory = join(root, "bundle");
|
|
// Whitespace preserves a valid manifest while making the actual file large.
|
|
await appendFile(files.manifestPath, Buffer.alloc(8 * 1024 * 1024, " "));
|
|
let available: number | undefined;
|
|
for (const phase of ["whole-read", "snapshot"] as const) {
|
|
if (available !== undefined) {
|
|
// Fit the native parse in two thirds of the previous child's real
|
|
// headroom, while the additional snapshot reservation cannot fit.
|
|
const overhead = nativeJsonParseRequiredBytes(0);
|
|
const perByte = nativeJsonParseRequiredBytes(1) - overhead;
|
|
await truncate(
|
|
files.manifestPath,
|
|
Math.max(
|
|
originalBytes,
|
|
Math.floor(((available * 2) / 3 - overhead) / perByte),
|
|
),
|
|
);
|
|
}
|
|
const result = await cli.run({
|
|
arguments: [
|
|
"environment-export",
|
|
files.manifestPath,
|
|
"--evidence",
|
|
files.capturePath,
|
|
directory,
|
|
"--json",
|
|
],
|
|
environment: {
|
|
NODE_OPTIONS: `--import=${probe} --max-old-space-size=256`,
|
|
REA_TEST_EXPORT_INPUT: files.manifestPath,
|
|
REA_TEST_EXPORT_READ_MARKER: marker,
|
|
REA_TEST_EXPORT_READ_ACTION: "record",
|
|
},
|
|
timeoutMs: 30_000,
|
|
});
|
|
expect(result.exitCode, result.stderr).toBe(1);
|
|
const limits = heapRefusalSchema.parse(result.json).details
|
|
.reported_limits;
|
|
expect(limits.input_path).toBe(files.manifestPath);
|
|
expect(limits.input_file_bytes).toBe(
|
|
(await stat(files.manifestPath)).size,
|
|
);
|
|
expect(limits.required_heap_bytes).toBe(
|
|
nativeJsonParseRequiredBytes(limits.input_file_bytes, true),
|
|
);
|
|
expect(limits.required_heap_bytes).toBeGreaterThan(
|
|
limits.available_heap_bytes,
|
|
);
|
|
if (phase === "snapshot")
|
|
expect(
|
|
nativeJsonParseRequiredBytes(limits.input_file_bytes),
|
|
).toBeLessThan(limits.available_heap_bytes);
|
|
else
|
|
expect(
|
|
nativeJsonParseRequiredBytes(limits.input_file_bytes),
|
|
).toBeGreaterThan(limits.available_heap_bytes);
|
|
available = limits.available_heap_bytes;
|
|
await expect(stat(marker)).rejects.toMatchObject({ code: "ENOENT" });
|
|
await expect(stat(directory)).rejects.toMatchObject({ code: "ENOENT" });
|
|
}
|
|
},
|
|
);
|
|
|
|
cliTest(
|
|
"attributes a pathless descriptor failure during the real tarball copy",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-export-copy-read-cli-");
|
|
const files = await writeEnvironmentServeFiles(root);
|
|
const tarball = join(root, "package.tgz");
|
|
await writeFile(tarball, "admitted package");
|
|
const marker = join(root, "read-marker");
|
|
const directory = join(root, "bundle");
|
|
const result = await cli.run({
|
|
arguments: [
|
|
"environment-export",
|
|
files.manifestPath,
|
|
"--evidence",
|
|
files.capturePath,
|
|
directory,
|
|
"--package-tarball",
|
|
tarball,
|
|
"--json",
|
|
],
|
|
environment: {
|
|
NODE_OPTIONS: `--import=${probe} --max-old-space-size=256`,
|
|
REA_TEST_EXPORT_INPUT: tarball,
|
|
REA_TEST_EXPORT_READ_MARKER: marker,
|
|
REA_TEST_EXPORT_READ_ACTION: "fail-copy",
|
|
},
|
|
timeoutMs: 30_000,
|
|
});
|
|
expect(await readFile(marker, "utf8")).toBe("copy");
|
|
expect(await readFile(tarball, "utf8")).toBe("admitted package");
|
|
expect(result.exitCode, result.stderr).toBe(1);
|
|
expect(result.json).toMatchObject({
|
|
code: "unreadable_output",
|
|
details: {
|
|
reason: expect.stringContaining(`reading ${tarball}`),
|
|
diagnostics: { output_directory: directory },
|
|
},
|
|
remediation: { action: expect.stringContaining(tarball) },
|
|
});
|
|
expect(JSON.stringify(result.json)).not.toContain("disk space");
|
|
},
|
|
);
|