import { describe, it, expect, beforeEach } from "vitest"; import { InMemoryQueue } from "./queue"; describe("InMemoryQueue", () => { let queue: InMemoryQueue; beforeEach(() => { queue = new InMemoryQueue(); }); it("enqueues a job with correct payload", async () => { const job = await queue.enqueue("darkwatch.scan", { userId: "user-1", subscriptionId: "sub-1", }); expect(job.type).toBe("darkwatch.scan"); expect(job.payload).toEqual({ userId: "user-1", subscriptionId: "sub-1" }); expect(job.status).toBe("pending"); expect(job.attempts).toBe(0); expect(job.maxAttempts).toBe(3); expect(job.id).toBeDefined(); }); it("dequeues pending jobs in order", async () => { await queue.enqueue("darkwatch.scan", { userId: "u1", subscriptionId: "s1" }); await queue.enqueue("hometitle.scan", { userId: "u2", subscriptionId: "s2" }); const job1 = await queue.dequeue(); expect(job1?.type).toBe("darkwatch.scan"); expect(job1?.status).toBe("running"); const job2 = await queue.dequeue(); expect(job2?.type).toBe("hometitle.scan"); expect(job2?.status).toBe("running"); const job3 = await queue.dequeue(); expect(job3).toBeNull(); }); it("only dequeues pending jobs", async () => { const job = await queue.enqueue("notifications.send", { userId: "u1", channel: "email" }); await queue.markComplete(job.id); const result = await queue.dequeue(); expect(result).toBeNull(); }); it("marks job as completed", async () => { const job = await queue.enqueue("reports.generate", { userId: "u1", reportType: "MONTHLY_PLUS" }); await queue.markComplete(job.id); const fetched = await queue.getJob(job.id); expect(fetched?.status).toBe("completed"); }); it("marks job as failed with error", async () => { const job = await queue.enqueue("voiceprint.batch", {}); await queue.markFailed(job.id, "Test error"); const fetched = await queue.getJob(job.id); expect(fetched?.status).toBe("failed"); expect(fetched?.error).toBe("Test error"); }); it("returns null for non-existent job", async () => { const job = await queue.getJob("non-existent"); expect(job).toBeNull(); }); it("filters jobs by status", async () => { const j1 = await queue.enqueue("darkwatch.scan", { userId: "u1", subscriptionId: "s1" }); const j2 = await queue.enqueue("hometitle.scan", { userId: "u2", subscriptionId: "s2" }); await queue.markComplete(j1.id); const pending = await queue.getJobs("pending"); expect(pending).toHaveLength(1); expect(pending[0].id).toBe(j2.id); const completed = await queue.getJobs("completed"); expect(completed).toHaveLength(1); expect(completed[0].id).toBe(j1.id); }); it("supports delayed enqueue", async () => { await queue.enqueue("notifications.send", { userId: "u1", channel: "email" }, { delay: 50 }); const immediate = await queue.dequeue(); expect(immediate).toBeNull(); await new Promise((r) => setTimeout(r, 60)); const delayed = await queue.dequeue(); expect(delayed?.type).toBe("notifications.send"); }); it("supports custom maxAttempts", async () => { const job = await queue.enqueue("removebrokers.process", {}, { maxAttempts: 5 }); expect(job.maxAttempts).toBe(5); }); });