| import { beforeEach, describe, expect, it, vi } from "vitest"; |
|
|
| const diagnosticMocks = vi.hoisted(() => ({ |
| logLaneEnqueue: vi.fn(), |
| logLaneDequeue: vi.fn(), |
| diag: { |
| debug: vi.fn(), |
| warn: vi.fn(), |
| error: vi.fn(), |
| }, |
| })); |
|
|
| vi.mock("../logging/diagnostic.js", () => ({ |
| logLaneEnqueue: diagnosticMocks.logLaneEnqueue, |
| logLaneDequeue: diagnosticMocks.logLaneDequeue, |
| diagnosticLogger: diagnosticMocks.diag, |
| })); |
|
|
| import { enqueueCommand, getQueueSize } from "./command-queue.js"; |
|
|
| describe("command queue", () => { |
| beforeEach(() => { |
| diagnosticMocks.logLaneEnqueue.mockClear(); |
| diagnosticMocks.logLaneDequeue.mockClear(); |
| diagnosticMocks.diag.debug.mockClear(); |
| diagnosticMocks.diag.warn.mockClear(); |
| diagnosticMocks.diag.error.mockClear(); |
| }); |
|
|
| it("runs tasks one at a time in order", async () => { |
| let active = 0; |
| let maxActive = 0; |
| const calls: number[] = []; |
|
|
| const makeTask = (id: number) => async () => { |
| active += 1; |
| maxActive = Math.max(maxActive, active); |
| calls.push(id); |
| await new Promise((resolve) => setTimeout(resolve, 15)); |
| active -= 1; |
| return id; |
| }; |
|
|
| const results = await Promise.all([ |
| enqueueCommand(makeTask(1)), |
| enqueueCommand(makeTask(2)), |
| enqueueCommand(makeTask(3)), |
| ]); |
|
|
| expect(results).toEqual([1, 2, 3]); |
| expect(calls).toEqual([1, 2, 3]); |
| expect(maxActive).toBe(1); |
| expect(getQueueSize()).toBe(0); |
| }); |
|
|
| it("logs enqueue depth after push", async () => { |
| const task = enqueueCommand(async () => {}); |
|
|
| expect(diagnosticMocks.logLaneEnqueue).toHaveBeenCalledTimes(1); |
| expect(diagnosticMocks.logLaneEnqueue.mock.calls[0]?.[1]).toBe(1); |
|
|
| await task; |
| }); |
|
|
| it("invokes onWait callback when a task waits past the threshold", async () => { |
| let waited: number | null = null; |
| let queuedAhead: number | null = null; |
|
|
| |
| const first = enqueueCommand(async () => { |
| await new Promise((resolve) => setTimeout(resolve, 30)); |
| }); |
|
|
| const second = enqueueCommand(async () => {}, { |
| warnAfterMs: 5, |
| onWait: (ms, ahead) => { |
| waited = ms; |
| queuedAhead = ahead; |
| }, |
| }); |
|
|
| await Promise.all([first, second]); |
|
|
| expect(waited).not.toBeNull(); |
| expect(waited as number).toBeGreaterThanOrEqual(5); |
| expect(queuedAhead).toBe(0); |
| }); |
| }); |
|
|