Files
SnowLuma/packages/common/tests/concurrency.test.ts
T
TanTan fa9c73363d
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
SnowLuma v2.4.2 source snapshot
2026-11-13 09:02:00 +08:00

82 lines
2.8 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { mapWithConcurrency } from '../src/concurrency';
const tick = () => new Promise<void>((r) => setTimeout(r, 0));
describe('mapWithConcurrency', () => {
it('returns results in input order', async () => {
const out = await mapWithConcurrency([1, 2, 3, 4, 5], 2, async (n) => n * 10);
expect(out).toEqual([10, 20, 30, 40, 50]);
});
it('passes the absolute index (across batch boundaries)', async () => {
const seen: Array<[number, number]> = [];
await mapWithConcurrency(['a', 'b', 'c', 'd', 'e'], 2, async (item, i) => {
seen.push([i, item.charCodeAt(0)]);
return i;
});
expect(seen.map(([i]) => i).sort((x, y) => x - y)).toEqual([0, 1, 2, 3, 4]);
});
it('never runs more than `concurrency` at once (batched), and serializes across batches', async () => {
let inFlight = 0;
let peak = 0;
const order: number[] = [];
await mapWithConcurrency([0, 1, 2, 3, 4, 5, 6], 3, async (n) => {
inFlight++;
peak = Math.max(peak, inFlight);
await tick();
order.push(n);
inFlight--;
return n;
});
expect(peak).toBeLessThanOrEqual(3);
// batched: first 3 (0,1,2) settle before the next batch (3,4,5) starts.
expect(order.slice(0, 3).sort((a, b) => a - b)).toEqual([0, 1, 2]);
expect(order.slice(3, 6).sort((a, b) => a - b)).toEqual([3, 4, 5]);
expect(order[6]).toBe(6);
});
it('handles a length not divisible by concurrency (short final batch)', async () => {
const out = await mapWithConcurrency([1, 2, 3, 4, 5], 3, async (n) => n);
expect(out).toEqual([1, 2, 3, 4, 5]);
});
it('runs everything in one batch when concurrency >= length', async () => {
let peak = 0,
inFlight = 0;
const out = await mapWithConcurrency([1, 2, 3], 10, async (n) => {
inFlight++;
peak = Math.max(peak, inFlight);
await tick();
inFlight--;
return n;
});
expect(out).toEqual([1, 2, 3]);
expect(peak).toBe(3);
});
it('returns [] for an empty input without calling fn', async () => {
let called = 0;
const out = await mapWithConcurrency([], 4, async (n) => {
called++;
return n;
});
expect(out).toEqual([]);
expect(called).toBe(0);
});
it('treats concurrency < 1 as 1 (fully serial)', async () => {
let peak = 0,
inFlight = 0;
await mapWithConcurrency([1, 2, 3], 0, async (n) => {
inFlight++;
peak = Math.max(peak, inFlight);
await tick();
inFlight--;
return n;
});
expect(peak).toBe(1);
});
});