feat(catalog): queue furniture imports with history and matching file attachments
This commit is contained in:
1 parent
775d14f861
commit
2619bec165
16 files changed
+1016
-232
No files matched your search
@@ -0,0 +1,61 @@
|
||||
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");
|
||||
});
|
||||
Reference in new issue
Block a user