Initial Commit
This commit is contained in:
103
packages/foundation/flow/job-scheduler/tests/property.test.ts
Normal file
103
packages/foundation/flow/job-scheduler/tests/property.test.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
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<string>();
|
||||
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 }
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user