62 lines
1.9 KiB
TypeScript
62 lines
1.9 KiB
TypeScript
import { randomUUID } from "node:crypto";
|
|
import { promises as fs } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
import { afterEach, expect, it } from "vitest";
|
|
import type { ImportJob } from "@/lib/furni/import-job";
|
|
import { ImportJobStore } from "./furni-job-store";
|
|
|
|
const roots: string[] = [];
|
|
afterEach(async () => {
|
|
for (const root of roots.splice(0))
|
|
await fs.rm(root, { recursive: true, force: true });
|
|
});
|
|
const job = (): ImportJob => ({
|
|
id: randomUUID(),
|
|
userId: 4,
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString(),
|
|
state: "queued",
|
|
translate: false,
|
|
items: [],
|
|
});
|
|
async function store() {
|
|
const root = await fs.mkdtemp(path.join(tmpdir(), "furni-jobs-test-"));
|
|
roots.push(root);
|
|
return new ImportJobStore(root);
|
|
}
|
|
it("persists history across store instances", async () => {
|
|
const s = await store(),
|
|
j = job();
|
|
await s.create(j);
|
|
expect(await new ImportJobStore(s.root).read(j.id)).toEqual(j);
|
|
});
|
|
it("deduplicates concurrent submissions of the same request", async () => {
|
|
const s = await store(),
|
|
j = job();
|
|
await Promise.all([s.create(j), s.create(j)]);
|
|
expect(await s.list()).toHaveLength(1);
|
|
});
|
|
it("does not overwrite a completed job on a repeated request", async () => {
|
|
const s = await store(),
|
|
j = job();
|
|
await s.create(j);
|
|
await s.save({ ...j, state: "completed" });
|
|
expect((await s.create(j)).state).toBe("completed");
|
|
});
|
|
it("rejects another user attempting to reuse an ID", async () => {
|
|
const s = await store(),
|
|
j = job();
|
|
await s.create(j);
|
|
await expect(s.create({ ...j, userId: 8 })).rejects.toThrow(
|
|
"Request ID already used",
|
|
);
|
|
});
|
|
it("rejects unsafe job paths", async () => {
|
|
const s = await store();
|
|
await expect(s.create({ ...job(), id: "../escape" })).rejects.toThrow(
|
|
"Invalid import ID",
|
|
);
|
|
await expect(s.read("../escape")).rejects.toThrow("Invalid import ID");
|
|
});
|