Files
OmniRoute/tests/unit/provider-limits-chunked-spacing-sync.test.ts

109 lines
3.0 KiB
TypeScript

/**
* Unit tests for the pure `syncInChunksWithSpacing` helper (#6916).
*
* Proves the chunking/spacing contract in isolation — no DB, no network —
* before it is wired into `syncAllProviderLimits()`'s OAuth and non-OAuth
* paths.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { syncInChunksWithSpacing } from "../../src/lib/usage/providerLimits/chunkedSpacingSync.ts";
test("waits between chunks but not after the last chunk when spacingMs > 0", async () => {
const items = [1, 2, 3, 4];
const chunkStarts: number[] = [];
const start = Date.now();
await syncInChunksWithSpacing(
items,
2,
40,
async (item) => {
chunkStarts.push(Date.now() - start);
return item;
},
() => {}
);
// 2 chunks of 2 → chunkStarts has 4 entries (2 per chunk, same start time).
assert.equal(chunkStarts.length, 4);
const chunk1Start = Math.min(chunkStarts[0], chunkStarts[1]);
const chunk2Start = Math.min(chunkStarts[2], chunkStarts[3]);
assert.ok(
chunk2Start - chunk1Start >= 35,
`expected >=35ms gap between chunks, got ${chunk2Start - chunk1Start}`
);
});
test("never waits when spacingMs === 0 (opt-out, preserves fast path)", async () => {
const items = [1, 2, 3, 4];
const start = Date.now();
await syncInChunksWithSpacing(items, 2, 0, async (item) => item, () => {});
const elapsed = Date.now() - start;
assert.ok(elapsed < 30, `expected near-instant run with spacingMs=0, took ${elapsed}ms`);
});
test("chunkSize=1 processes items strictly one at a time (reproduces OAuth semantics)", async () => {
const items = ["a", "b", "c"];
const chunks: string[][] = [];
await syncInChunksWithSpacing(
items,
1,
0,
async (item) => item,
(chunk) => chunks.push([...chunk])
);
assert.deepEqual(chunks, [["a"], ["b"], ["c"]]);
});
test("preserves in-chunk concurrency — all items in a chunk start before any resolves", async () => {
const items = [1, 2, 3];
let inFlight = 0;
let maxInFlight = 0;
await syncInChunksWithSpacing(
items,
3,
0,
async (item) => {
inFlight++;
maxInFlight = Math.max(maxInFlight, inFlight);
await new Promise((resolve) => setTimeout(resolve, 20));
inFlight--;
return item;
},
() => {}
);
assert.equal(maxInFlight, 3, "all 3 items in the single chunk should overlap");
});
test("delivers chunk + results to onChunkResults, including rejections", async () => {
const items = [1, 2, 3];
const seen: Array<{ chunk: number[]; statuses: string[] }> = [];
await syncInChunksWithSpacing(
items,
2,
0,
async (item) => {
if (item === 2) throw new Error("boom");
return item * 10;
},
(chunk, results) => {
seen.push({ chunk: [...chunk], statuses: results.map((r) => r.status) });
}
);
assert.equal(seen.length, 2);
assert.deepEqual(seen[0].chunk, [1, 2]);
assert.deepEqual(seen[0].statuses, ["fulfilled", "rejected"]);
assert.deepEqual(seen[1].chunk, [3]);
assert.deepEqual(seen[1].statuses, ["fulfilled"]);
});