Files
morluto 60149282fc test: strengthen integration oracles and verification (#8295)
* test: strengthen integration oracles and verification

* test: bound lifecycle gates and strengthen workflow checks

* test: verify complete paged and extracted results

* test: preserve bytecode and cancellation evidence

* test: strengthen retained evidence and fixture cleanup

* test: require cross-projection bridge identities

* test: retain fixture owners through cleanup failures

* test: verify graph examples and project selectors

* test: tighten provider and lifecycle regressions

* test: consolidate hex coverage and bound cutter cleanup

* test: bound subprocess output waits and strengthen graph checks

* test: check mcp recovery and preserve cleanup owners

* test: verify structured mcp argument failures

* test: preserve artifact cleanup and gdb limit evidence

* test: preserve evidence identities and bound provider gates

* test: retain browser and comparison cleanup owners

* test: bound startup and strengthen fixture oracles

* test: bound lifecycle gates and verify recovered evidence

* test: verify public outcomes and lifecycle ownership

* test: assert precise evidence and release lifecycle gates

* test: verify selected facts and bound cleanup waits

* test: check retained evidence and decoded records

* test: verify final reports and retain cleanup ownership

* test: bound reviewed startup gates and retain cleanup

* test: verify PE errors and preserve MCP cleanup

* test: preserve MCP fixture cleanup ownership

* test: release provider gates before late startup
2026-11-01 00:15:28 +08:00

323 lines
9.8 KiB
TypeScript

import { execFileSync } from "node:child_process";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { describe, expect, it } from "vitest";
import {
BUILT_TEST_PROJECTS,
SOURCE_TEST_PROJECTS,
projectForTest,
} from "../../../scripts/lib/test-projects.mjs";
import {
developmentTestPlan,
parseDevelopmentTestRequest,
} from "../../../scripts/lib/development-tests.mjs";
import {
execFileOutput,
execFileOutputFailure,
} from "../../../src/process/ExecFileOutput.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { writeRepositoryOxlintConfiguration } from "../../fixtures/oxlintConfiguration.js";
const repository = process.cwd();
const oxlint = join(repository, "node_modules/oxlint/bin/oxlint");
const oxlintConfig = join(repository, ".oxlintrc.json");
const runOxlint = async (
cwd: string,
config: string,
files: readonly string[],
) => {
let stdout: string;
let exitCode: string | number = 0;
try {
({ stdout } = await execFileOutput(
process.execPath,
[oxlint, "--threads=1", "--config", config, "--format", "json", ...files],
{
cwd,
timeout: 60_000,
maxBuffer: 8 * 1024 * 1024,
stopSignal: "SIGTERM",
},
));
} catch (cause) {
const failure = execFileOutputFailure(cause);
if (
failure === undefined ||
failure.code !== 1 ||
failure.signal !== null ||
failure.killed ||
failure.outputTruncated
)
throw cause;
stdout = failure.stdout;
exitCode = failure.code;
}
return {
exitCode,
report: JSON.parse(stdout) as {
diagnostics?: Array<{ code?: string; severity: string }>;
},
};
};
describe("canonical test-project ownership", () => {
it("assigns every tracked test file exactly once to source or built", () => {
const files = execFileSync("git", ["ls-files", "*.test.ts"], {
cwd: repository,
encoding: "utf8",
})
.trim()
.split("\n")
.filter(Boolean);
const grouped = new Map<string, string[]>();
for (const file of files) {
const project = projectForTest(file);
grouped.set(project.group, [...(grouped.get(project.group) ?? []), file]);
}
expect(grouped.get("source")).not.toBeUndefined();
expect(grouped.get("built")).not.toBeUndefined();
expect(
(grouped.get("source")?.length ?? 0) +
(grouped.get("built")?.length ?? 0),
).toBe(files.length);
expect(
SOURCE_TEST_PROJECTS.reduce(
(count, project) => count + project.include.length,
0,
),
).toBeGreaterThan(0);
expect(
BUILT_TEST_PROJECTS.every((project) => project.group === "built"),
).toBe(true);
expect(() => projectForTest("tests/unowned/example.test.ts")).toThrow(
"No test project owns",
);
});
it("owns the Hopper real-provider conformance test as built and requires preparation", () => {
const testPath =
"tests/conformance/providers/hopper/realHopperSearch.test.ts";
expect(projectForTest(testPath)).toMatchObject({
name: "boundary",
group: "built",
});
expect(() => parseDevelopmentTestRequest("local", [testPath])).toThrow(
`Use test:focused for built test projects: ${testPath}`,
);
const request = parseDevelopmentTestRequest("focused", [testPath]);
expect(developmentTestPlan(request)).toMatchObject({ needsBuild: true });
});
});
describe("Vitest project configuration", () => {
it("uses canonical test-project selectors in Vitest", async () => {
const root = await createTestTempDirectory("rea-vitest-project-selectors-");
const script = join(root, "project-selectors.mjs");
await writeFile(
script,
`
const { default: config } = await import(process.argv[2]);
console.log(JSON.stringify(config.test.projects.map(({ test }) => ({
name: test.name,
include: test.include,
exclude: test.exclude ?? [],
}))));
`,
);
const result = await execFileOutput(
process.execPath,
[
"--import",
"tsx",
script,
pathToFileURL(join(repository, "vitest.config.ts")).href,
],
{
cwd: repository,
timeout: 10_000,
maxBuffer: 64 * 1024,
stopSignal: "SIGTERM",
},
);
const selectors = JSON.parse(result.stdout) as Array<{
name: string;
include: string[];
exclude: string[];
}>;
const canonical = [...SOURCE_TEST_PROJECTS, ...BUILT_TEST_PROJECTS].map(
({ name, include, exclude }) => ({
name,
include,
exclude: exclude ?? [],
}),
);
expect(selectors.sort((a, b) => a.name.localeCompare(b.name))).toEqual(
canonical.sort((a, b) => a.name.localeCompare(b.name)),
);
});
it.each([
{ flags: [], timeout: 30_000, lines: 68 },
{ flags: ["--coverage"], timeout: 60_000, lines: 68 },
{ flags: ["--coverage.enabled"], timeout: 60_000, lines: 68 },
{ flags: ["--coverage=false"], timeout: 30_000, lines: 68 },
{
flags: ["--coverage.enabled=false"],
timeout: 30_000,
lines: 68,
},
{
flags: ["--coverage.provider=v8"],
timeout: 30_000,
lines: 68,
},
{
flags: ["--coverage.enabled", "--shard", "1/6"],
timeout: 60_000,
lines: 0,
},
{
flags: ["--coverage.enabled=false", "--shard=1/6"],
timeout: 30_000,
lines: 0,
},
])(
"resolves worker resources from actual CLI options: $flags",
async ({ flags, timeout, lines }) => {
const root = await createTestTempDirectory("rea-vitest-worker-policy-");
const script = join(root, "worker-policy.mjs");
await writeFile(
script,
`
import config from ${JSON.stringify(pathToFileURL(join(repository, "vitest.config.ts")).href)};
const project = config.test.projects.find(project => project.test.name === 'cli-boundary');
console.log(JSON.stringify({
execArgv: project.test.execArgv,
timeout: config.test.testTimeout,
lines: config.test.coverage.thresholds.lines,
}));
`,
);
const result = await execFileOutput(
process.execPath,
["--import", "tsx", script, ...flags],
{
cwd: repository,
timeout: 10_000,
maxBuffer: 64 * 1024,
stopSignal: "SIGTERM",
},
);
expect(JSON.parse(result.stdout)).toEqual({
execArgv: ["--max-old-space-size=512"],
timeout,
lines,
});
},
);
});
describe("test module isolation", () => {
it.each([
[
"tests/process-global/evidenceBundleHeadroom.test.ts",
"process-global",
"built",
],
[
"tests/process-global/javascriptAnalysisCancellation.test.ts",
"process-global",
"built",
],
])("keeps %s in its isolated preparation group", (path, name, group) => {
expect(projectForTest(path)).toMatchObject({ name, group });
});
it("uses one isolation policy for Vitest and binding-aware mock lint", async () => {
const files = execFileSync("git", ["ls-files", "*.test.ts"], {
cwd: repository,
encoding: "utf8",
})
.trim()
.split("\n")
.filter(Boolean);
const root = await createTestTempDirectory("rea-vitest-project-policy-");
const script = join(root, "project-isolation.mjs");
await writeFile(
script,
`
import config from ${JSON.stringify(pathToFileURL(join(repository, "vitest.config.ts")).href)};
console.log(JSON.stringify(Object.fromEntries(
config.test.projects.map(project => [project.test.name, project.test.isolate]),
)));
`,
);
const result = await execFileOutput(
process.execPath,
["--import", "tsx", script],
{
cwd: repository,
timeout: 10_000,
maxBuffer: 64 * 1024,
stopSignal: "SIGTERM",
},
);
const isolated = JSON.parse(result.stdout) as Record<string, boolean>;
expect(files.length).toBeGreaterThan(0);
expect(
files.filter((file) => {
const project = projectForTest(file);
return isolated[project.name] !== (project.isolate !== false);
}),
).toEqual([]);
const { report } = await runOxlint(repository, oxlintConfig, files);
expect(
report.diagnostics?.filter(
({ code, severity }) =>
code === "rea(no-shared-module-mock)" && severity === "error",
),
).toEqual([]);
});
it("rejects actual Vitest module-mock aliases only in shared projects", async () => {
const root = await createTestTempDirectory("rea-vitest-mock-probe-");
const sharedDirectory = join(root, "tests/evaluation");
const isolatedDirectory = join(root, "tests/process-global");
await mkdir(sharedDirectory, { recursive: true });
await mkdir(isolatedDirectory, { recursive: true });
const config = await writeRepositoryOxlintConfiguration(root);
const probe = async (directory: string, source: string) => {
const path = join(directory, "mock-probe.test.ts");
await writeFile(path, source);
return runOxlint(root, config, [path]);
};
const shared = await probe(
sharedDirectory,
'import { vi as testing } from "vitest"; testing.mock("./dependency.js");',
);
const isolated = await probe(
isolatedDirectory,
'import * as testing from "vitest"; testing.vi.doMock("./dependency.js");',
);
expect(shared.exitCode).toBe(1);
expect(
shared.report.diagnostics?.filter(
({ code, severity }) =>
code === "rea(no-shared-module-mock)" && severity === "error",
),
).toHaveLength(1);
expect(isolated.exitCode).toBe(0);
expect(
isolated.report.diagnostics?.filter(
({ code }) => code === "rea(no-shared-module-mock)",
),
).toEqual([]);
});
});