Files
reverse-engineering-anything/tests/boundary/filesystem/ciPortableBuildCache.test.ts
T
Ysopwnable 2092f90b7e perf(ci): upload only current portable build cache entries
Stage only the current portable Turbo task archives, metadata and available manifests for same-run artifact consumers. Share task identity/hash validation with cross-run keys and fail publication on incomplete preparation, while retaining existing cache authority and consumer build/prepack verification.

Validation: 252 focused tests, full check:ci, docs:check, check:fast, actionlint, real Turbo output equivalence and invalidation, restored CLI/MCP scenarios and full Linux package verification passed. Fault injection detected historical-entry inclusion. Exact-head hosted CI and available review passed; measurement limits are recorded in the PR.

Refs #4744.
2026-10-17 09:44:11 +00:00

177 lines
6.1 KiB
TypeScript

import { spawnSync } from "node:child_process";
import { createHash } from "node:crypto";
import {
mkdir,
readFile,
readdir,
rm,
symlink,
writeFile,
} from "node:fs/promises";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { expect, it } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const script = fileURLToPath(
new URL("../../../scripts/ci/portable-build-cache.mjs", import.meta.url),
);
const first = { taskId: "compile", hash: "0123456789abcdef" };
const second = { taskId: "artifacts:skills", hash: "fedcba9876543210" };
const plan = { tasks: [first, second] };
const prefix = "rea-portable-build-v2-Linux-X64-toolchain";
const output = ".cache/ci-build-cache";
function run(root: string, mode: "key" | "snapshot", input: unknown = plan) {
const result = spawnSync(process.execPath, [script, mode], {
cwd: root,
input: typeof input === "string" ? input : JSON.stringify(input),
encoding: "utf8",
env: { ...process.env, BUILD_CACHE_PREFIX: prefix },
});
expect(result.error).toBeUndefined();
return result;
}
async function fixture() {
const root = await createTestTempDirectory("rea-ci-portable-cache-");
await mkdir(join(root, ".turbo/cache"), { recursive: true });
return root;
}
async function entry(root: string, hash: string, manifest = true) {
for (const suffix of [
".tar.zst",
"-meta.json",
...(manifest ? ["-manifest.json"] : []),
])
await writeFile(
join(root, ".turbo/cache", `${hash}${suffix}`),
`${hash}${suffix}\n`,
);
}
async function inventory(root: string, path: string) {
const files = (await readdir(join(root, path))).sort();
return Promise.all(
files.map(async (name) => [
name,
await readFile(join(root, path, name), "hex"),
]),
);
}
it("publishes only current task companions without changing the source cache or retaining old snapshots", async () => {
const root = await fixture();
await entry(root, first.hash);
await entry(root, second.hash, false);
await entry(root, "aaaaaaaaaaaaaaaa");
const before = await inventory(root, ".turbo/cache");
const result = run(root, "snapshot");
expect(result.status, result.stderr).toBe(0);
const current = before.filter(
([name]) => name?.startsWith(first.hash) || name?.startsWith(second.hash),
);
expect(await inventory(root, output)).toEqual(current);
expect(JSON.parse(result.stdout)).toMatchObject({
tasks: 2,
files: 5,
path: output,
});
expect(run(root, "snapshot", { tasks: [second] }).status).toBe(0);
expect(await inventory(root, output)).toEqual(
before.filter(([name]) => name?.startsWith(second.hash)),
);
expect(await inventory(root, ".turbo/cache")).toEqual(before);
});
it("retains existing cross-run keys independent of plan order and invalidates changed task hashes", async () => {
const root = await fixture();
const digest = createHash("sha256")
.update(
plan.tasks
.map(({ taskId, hash }) => `${taskId}:${hash}`)
.sort()
.join("\n"),
)
.digest("hex");
const expected = `key=${prefix}-${digest}\nprefix=${prefix}-\n`;
const result = run(root, "key");
expect(result.status, result.stderr).toBe(0);
expect(result.stdout).toBe(expected);
expect(run(root, "key", { tasks: [second, first] }).stdout).toBe(expected);
const changed = run(root, "key", {
tasks: [first, { ...second, hash: "aaaaaaaaaaaaaaaa" }],
});
expect(changed.status, changed.stderr).toBe(0);
expect(changed.stdout).not.toBe(expected);
});
it("rejects malformed or ambiguous plans in both commands and removes stale publication output", async () => {
const root = await fixture();
for (const invalid of [
"not JSON",
{},
{ tasks: [] },
{ tasks: [{ taskId: "compile" }] },
{ tasks: [{ ...first, hash: null }] },
{ tasks: [{ ...first, hash: "../outside" }] },
{ tasks: [first, { ...first, hash: second.hash }] },
]) {
await mkdir(join(root, output), { recursive: true });
await writeFile(join(root, output, "old-success"), "stale");
for (const mode of ["key", "snapshot"] as const) {
const result = run(root, mode, invalid);
expect(result.status, result.stderr).not.toBe(0);
expect(result.stdout).toBe("");
}
await expect(readdir(join(root, output))).rejects.toMatchObject({
code: "ENOENT",
});
}
});
it("fails publication on a cold cache, missing companions or non-file entries, including after a partial copy", async () => {
const root = await fixture();
expect(run(root, "snapshot").status).not.toBe(0);
await expect(readdir(join(root, output))).rejects.toMatchObject({
code: "ENOENT",
});
await entry(root, first.hash);
for (const suffix of [".tar.zst", "-meta.json", "-manifest.json"]) {
await entry(root, second.hash);
const path = join(root, ".turbo/cache", `${second.hash}${suffix}`);
await rm(path);
if (suffix === "-manifest.json") await mkdir(path);
const result = run(root, "snapshot");
expect(result.status, result.stderr).not.toBe(0);
await expect(readdir(join(root, output))).rejects.toMatchObject({
code: "ENOENT",
});
await rm(path, { recursive: true, force: true });
}
});
it.skipIf(process.platform === "win32")(
"rejects symlinked archives and optional manifests without copying their targets",
async () => {
const root = await fixture();
const outside = join(root, "outside");
await writeFile(outside, "must not publish");
for (const suffix of [".tar.zst", "-manifest.json"]) {
await entry(root, first.hash);
const path = join(root, ".turbo/cache", `${first.hash}${suffix}`);
await rm(path);
await symlink(outside, path);
const result = run(root, "snapshot", { tasks: [first] });
expect(result.status, result.stderr).not.toBe(0);
expect(result.stderr).toContain("must be a regular file");
await expect(readdir(join(root, output))).rejects.toMatchObject({
code: "ENOENT",
});
expect(await readFile(outside, "utf8")).toBe("must not publish");
await rm(path);
}
},
);