import { describe, expect, it } from "@suaveplan/testing/runner"; import fc from "fast-check"; import { JobQueue } from "../src/queue/job-queue.js"; describe("property: JobQueue monotonic dequeue", () => { it("always returns entries in non-decreasing runAt order", { timeout: 30_000, }, () => { fc.assert( fc.property( fc.array( fc.record({ jobId: fc.string({ minLength: 1, maxLength: 8 }), runAt: fc.integer({ min: 0, max: 1_000_000 }), }), { minLength: 0, maxLength: 200 } ), (entries) => { const q = new JobQueue(); for (let i = 0; i < entries.length; i++) { const e = entries[i] as { jobId: string; runAt: number; }; q.enqueue({ jobId: `${e.jobId}-${i}`, runAt: e.runAt, }); } let prev = Number.NEGATIVE_INFINITY; while (q.size() > 0) { const out = q.dequeue(); if (out === undefined) break; expect(out.runAt).toBeGreaterThanOrEqual(prev); prev = out.runAt; } } ), { numRuns: 100 } ); }); }); describe("property: enqueue+remove leaves consistent heap", () => { it("after removing every inserted id, queue is empty", { timeout: 30_000, }, () => { fc.assert( fc.property( fc.array( fc.record({ jobId: fc.uuid(), runAt: fc.integer({ min: 0, max: 1_000_000 }), }), { minLength: 0, maxLength: 100 } ), (entries) => { const q = new JobQueue(); const ids = new Set(); for (const e of entries) { if (ids.has(e.jobId)) continue; ids.add(e.jobId); q.enqueue({ jobId: e.jobId, runAt: e.runAt }); } for (const id of ids) { expect(q.remove(id)).toBe(true); } expect(q.size()).toBe(0); expect(q.peek()).toBeUndefined(); } ), { numRuns: 100 } ); }); }); describe("property: enqueue followed by N dequeues equals sorted input", () => { it("produces a sorted output prefix", { timeout: 30_000 }, () => { fc.assert( fc.property( fc.array(fc.integer({ min: 0, max: 1_000_000 }), { minLength: 1, maxLength: 50, }), (runAts) => { const q = new JobQueue(); runAts.forEach((runAt, i) => { q.enqueue({ jobId: `j-${i}`, runAt }); }); const got: number[] = []; while (q.size() > 0) { const e = q.dequeue(); if (e === undefined) break; got.push(e.runAt); } const expected = [...runAts].sort((a, b) => a - b); expect(got).toEqual(expected); } ), { numRuns: 100 } ); }); });