storage.test.ts

3.1 KB · raw

1// Covers §24's Storage section: sizes by repo and kind, kept tarballs with a delete each, and2// orphan cleanup that touches only Kepr's own files.34import { beforeAll, describe, expect, test } from "bun:test";5import { mkdir, writeFile } from "node:fs/promises";6import { dirname, join } from "node:path";7import { Browser, type Instance, instance } from "./browser.ts";8import { makeRepos, writeRelease } from "./fixture.ts";910describe("storage view (§24)", () => {11	let inst: Instance;12	let operator: Browser;13	let bucketDir: string;14	let save: string;15	const exists = (key: string) => Bun.file(join(bucketDir, key)).exists();16	const put = async (key: string) => {17		await mkdir(dirname(join(bucketDir, key)), { recursive: true });18		await writeFile(join(bucketDir, key), "x");19	};20	let generation = "";21	const kept = () => `.kepr/tarballs/app/${generation}/${save}.tar.gz`;22	const orphans = [23		".kepr/tarballs/app/0-000000000000/aaaaaaaaaaaa.tar.gz",24		".kepr/tarballs/gone/0-000000000000/aaaaaaaaaaaa.tar.gz",25		".kepr/hidden/gone",26	];27	const unlisted = "app/releases/9.9.9/linux-x86_64/app";2829	beforeAll(async () => {30		const repos = await makeRepos(["app"]);31		bucketDir = repos.bucketDir;32		save = repos.saves.app as string;33		await writeRelease(bucketDir, "app", {34			version: "1.0.0",35			save,36			files: [{ platform: "linux-x86_64", name: "app", bytes: new Uint8Array(2048) }],37		});38		inst = await instance(bucketDir);39		operator = new Browser(inst.app);40		await operator.signIn();41		await operator.post("/admin/repos/app", { public: "1" });42		expect((await inst.app.request(`/app/archive/${save}.tar.gz`)).status).toBe(200);43		const listed = new Bun.Glob(`.kepr/tarballs/app/*/${save}.tar.gz`).scanSync({44			cwd: bucketDir,45			dot: true,46		});47		generation = (Array.from(listed)[0] as string).split("/")[3] as string;48		for (const key of [...orphans, unlisted]) await put(key);49	});5051	test("shows each repo's history, builds and kept tarballs, and the orphans", async () => {52		const page = await (await operator.get("/admin/storage")).text();53		expect(page).toMatch(/<td>app<\/td>\s*<td>[\d.]+ K?B<\/td>\s*<td>2\.\d KB<\/td>/);54		expect(page).toContain(`${save}.tar.gz`);55		expect(page).toContain("3 orphans");56	});5758	test("deleting orphans removes only Kepr's stale files", async () => {59		expect((await operator.post("/admin/storage", { action: "delete_orphans" })).status).toBe(303);60		for (const key of orphans) expect(await exists(key)).toBe(false);61		expect(await exists(kept())).toBe(true);62		expect(await exists(unlisted)).toBe(true);63		expect(await (await operator.get("/admin/storage")).text()).toContain("no orphans");64	});6566	test("one kept tarball can be deleted; any other key is a 404", async () => {67		const other = { action: "delete_tarball", key: "app/releases/1.0.0/linux-x86_64/app" };68		expect((await operator.post("/admin/storage", other)).status).toBe(404);69		expect(await exists("app/releases/1.0.0/linux-x86_64/app")).toBe(true);70		const response = await operator.post("/admin/storage", {71			action: "delete_tarball",72			key: kept(),73		});74		expect(response.status).toBe(303);75		expect(await exists(kept())).toBe(false);76	});77});