import { describe, expect, test } from "bun:test"; import { BackgroundBuildReconciler, DEFAULT_BUILD_RECONCILE_MS, DEFAULT_BUILD_RECONCILE_TIMEOUT_MS, MAX_BUILD_RECONCILE_TIMEOUT_MS, MAX_BUILD_RECONCILE_MS, buildReconcileIntervalMs, buildReconcileTimeoutMs, } from "../../server/build-reconciler"; describe("build reconciliation interval", () => { test("uses positive finite configured intervals and defaults invalid values", () => { expect(buildReconcileIntervalMs("1500")).toBe(1500); expect(buildReconcileIntervalMs(String(MAX_BUILD_RECONCILE_MS))).toBe( MAX_BUILD_RECONCILE_MS, ); for (const value of [ undefined, "", "0", "-1", "Infinity", "nope", String(MAX_BUILD_RECONCILE_MS + 1), ]) expect(buildReconcileIntervalMs(value)).toBe(DEFAULT_BUILD_RECONCILE_MS); }); }); describe("background build reconciliation", () => { test("does not overlap a timed-out scan and resumes after it settles", async () => { const scans: AbortSignal[] = []; let expire!: () => void; let releaseFirst!: () => void; let firstSettled!: () => void; const firstReleased = new Promise((resolve) => { releaseFirst = resolve; }); const settled = new Promise((resolve) => { firstSettled = resolve; }); const failures: unknown[] = []; const reconciler = new BackgroundBuildReconciler({ runner: { reconcilePendingBuilds: async ({ signal } = {}) => { scans.push(signal!); if (scans.length === 1) { await firstReleased; firstSettled(); } }, }, timeoutMs: 100, onFailure: (error) => failures.push(error), setTimeout: ((callback: () => void) => { expire = callback; return 0 as unknown as ReturnType; }) as typeof setTimeout, clearTimeout: (() => {}) as typeof clearTimeout, }); reconciler.tick(); reconciler.tick(); expect(scans).toHaveLength(1); expire(); expect(scans[0]!.aborted).toBe(true); reconciler.tick(); await Promise.resolve(); expect(scans).toHaveLength(1); expect(failures).toHaveLength(1); releaseFirst(); await settled; await Promise.resolve(); await Promise.resolve(); reconciler.tick(); await Promise.resolve(); expect(scans).toHaveLength(2); }); test("uses positive finite configured timeouts and defaults invalid values", () => { expect(buildReconcileTimeoutMs("1500")).toBe(1500); expect( buildReconcileTimeoutMs(String(MAX_BUILD_RECONCILE_TIMEOUT_MS)), ).toBe(MAX_BUILD_RECONCILE_TIMEOUT_MS); for (const value of [ undefined, "", "0", "-1", "Infinity", "nope", String(MAX_BUILD_RECONCILE_TIMEOUT_MS + 1), ]) expect(buildReconcileTimeoutMs(value)).toBe( DEFAULT_BUILD_RECONCILE_TIMEOUT_MS, ); }); });