feat: v2
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user