Files

54 lines
2.1 KiB
TypeScript

import { afterEach, beforeEach, expect, test } from "bun:test";
import { mkdtemp, readdir, rm, stat } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { forEachDialect } from "@sttracker/db/testing";
import { backupHandler, runBackup } from "../src/backup.ts";
import { makeUser } from "./user-layer-fixtures.ts";
forEachDialect("backup", (getDb) => {
let dir: string;
beforeEach(async () => {
dir = await mkdtemp(join(tmpdir(), "sttracker-bak-"));
});
afterEach(async () => {
await rm(dir, { recursive: true, force: true });
});
test("backup writes a bundle per user (and the db on sqlite)", async () => {
const db = getDb();
await makeUser(db, "ada");
await makeUser(db, "bob");
const out = await runBackup(db, dir, { keep: 14 });
expect(out.startsWith(join(dir, "backups"))).toBe(true);
const files = (await readdir(out)).sort();
expect(files).toEqual(db.dialect === "sqlite" ? ["ada.zip", "bob.zip", "sttracker.db"] : ["ada.zip", "bob.zip"]);
});
test("backup prunes to keep", async () => {
const db = getDb();
await makeUser(db, "ada");
const made: string[] = [];
for (let i = 0; i < 4; i++) made.push(await runBackup(db, dir, { keep: 2 }));
const left = (await readdir(join(dir, "backups"))).sort();
expect(left).toHaveLength(2);
expect(left.map((n) => join(dir, "backups", n))).toEqual(made.slice(2));
});
test("backupHandler runs a backup", async () => {
const db = getDb();
await makeUser(db, "ada");
await backupHandler({ db, dataDir: dir, keep: 3 })();
expect(await readdir(join(dir, "backups"))).toHaveLength(1);
});
test("backup files are private and no partial directory remains", async () => {
const db = getDb();
await makeUser(db, "ada");
const out = await runBackup(db, dir, { keep: 5 });
expect((await stat(out)).mode & 0o777).toBe(0o700);
expect((await stat(join(out, "ada.zip"))).mode & 0o777).toBe(0o600);
expect((await readdir(join(dir, "backups"))).some((n) => n.endsWith(".tmp"))).toBe(false);
});
});