Files
2026-09-03 11:28:30 +07:00

72 lines
2.6 KiB
TypeScript

import { afterEach, describe, expect, test } from "bun:test";
import { createHash } from "node:crypto";
import { mkdir, mkdtemp, rm, symlink, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { FilesystemCas } from "../../server/cas";
import type { Sha256Digest } from "../../shared/build-protocol";
const roots: string[] = [];
afterEach(async () => {
await Promise.all(
roots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
);
});
function digest(value: string): Sha256Digest {
return `sha256:${createHash("sha256").update(value).digest("hex")}`;
}
describe("filesystem CAS", () => {
test("stores, deduplicates, and verifies blobs", async () => {
const root = await mkdtemp(join(tmpdir(), "kuber-cas-"));
roots.push(root);
const cas = new FilesystemCas(root);
const expected = digest("hello");
expect(await cas.put(Buffer.from("hello"), expected)).toBe(expected);
expect(await cas.has(expected)).toBe(true);
expect(Buffer.from(await cas.get(expected)).toString()).toBe("hello");
expect(
await Promise.all(
Array.from({ length: 8 }, () => cas.put(Buffer.from("hello"))),
),
).toEqual(Array(8).fill(expected));
await expect(cas.put(Buffer.from("other"), expected)).rejects.toThrow(
"digest mismatch",
);
});
test("detects corruption on reads and existing writes", async () => {
const root = await mkdtemp(join(tmpdir(), "kuber-cas-"));
roots.push(root);
const cas = new FilesystemCas(root);
const expected = await cas.put(Buffer.from("hello"));
const hex = expected.slice(7);
await writeFile(
join(root, "sha256", hex.slice(0, 2), hex.slice(2)),
"tampered",
);
await expect(cas.get(expected)).rejects.toThrow("Corrupt CAS blob");
await expect(cas.put(Buffer.from("hello"))).rejects.toThrow(
"Corrupt CAS blob",
);
});
test("does not follow a blob-path symlink", async () => {
const root = await mkdtemp(join(tmpdir(), "kuber-cas-"));
const outside = await mkdtemp(join(tmpdir(), "kuber-cas-outside-"));
roots.push(root, outside);
const cas = new FilesystemCas(root);
const expected = digest("hello");
const hex = expected.slice(7);
await writeFile(join(outside, "blob"), "hello");
await mkdir(join(root, "sha256", hex.slice(0, 2)), { recursive: true });
await symlink(
join(outside, "blob"),
join(root, "sha256", hex.slice(0, 2), hex.slice(2)),
);
expect(await cas.has(expected)).toBe(false);
await expect(cas.get(expected)).rejects.toThrow();
});
});