/** * tests/unit/ui/comboFlowModel-cooldown.test.ts * * TDD for F5.1 (Combo U1b Slice 2) — enrichRunWithConnectionCooldown: overlays the * real per-provider connection-cooldown summary (from GET /api/monitoring/health → * connectionHealth[provider]) onto a combo run's targets, so the cascade can badge * "cooldown 2/3 · 28s" alongside the circuit-breaker badge. * * Mirrors comboFlowModel-breakers.test.ts (Slice 1). * Run: node --import tsx/esm --test tests/unit/ui/comboFlowModel-cooldown.test.ts */ import { describe, it } from "node:test"; import assert from "node:assert/strict"; import { enrichRunWithConnectionCooldown, comboRunToFlow, type ComboRunModel, type TargetNodeModel, } from "../../../src/app/(dashboard)/dashboard/combos/live/comboFlowModel.ts"; function mkRun(targets: Array & { provider: string }>): ComboRunModel { return { comboName: "c", strategy: "priority", outcome: "running", startedAt: 0, targets: targets.map((t, i) => ({ targetIndex: i, provider: t.provider, model: t.model ?? "m", state: t.state ?? "idle", ...t, })), }; } describe("enrichRunWithConnectionCooldown", () => { it("returns null for a null run", () => { assert.equal(enrichRunWithConnectionCooldown(null, {}), null); }); it("returns the same run reference when no health map is provided", () => { const run = mkRun([{ provider: "openai" }]); assert.equal(enrichRunWithConnectionCooldown(run, null), run); assert.equal(enrichRunWithConnectionCooldown(run, undefined), run); }); it("attaches cooldown count/total/retry for a provider with cooling connections", () => { const run = mkRun([{ provider: "anthropic" }, { provider: "openai" }]); const out = enrichRunWithConnectionCooldown(run, { anthropic: { coolingDown: 2, total: 3, soonestRetryAfterMs: 28_000 }, }); assert.ok(out); assert.equal(out.targets[0].cooldownCount, 2); assert.equal(out.targets[0].cooldownTotal, 3); assert.equal(out.targets[0].cooldownRetryAfterMs, 28_000); assert.equal( out.targets[1].cooldownCount, undefined, "provider with no cooldown gets no badge" ); }); it("does not attach a badge when coolingDown is 0 or absent", () => { const run = mkRun([{ provider: "a" }, { provider: "b" }]); const out = enrichRunWithConnectionCooldown(run, { a: { coolingDown: 0, total: 2, soonestRetryAfterMs: 0 }, b: {}, }); assert.equal(out?.targets[0].cooldownCount, undefined); assert.equal(out?.targets[1].cooldownCount, undefined); }); it("does not mutate the input run (pure)", () => { const run = mkRun([{ provider: "openai" }]); enrichRunWithConnectionCooldown(run, { openai: { coolingDown: 1, total: 1, soonestRetryAfterMs: 5000 }, }); assert.equal(run.targets[0].cooldownCount, undefined, "original run must be untouched"); }); it("strips a stale cooldown badge when the provider's connections recover", () => { const run = mkRun([ { provider: "openai", cooldownCount: 2, cooldownTotal: 3, cooldownRetryAfterMs: 9000 }, ]); const out = enrichRunWithConnectionCooldown(run, { openai: { coolingDown: 0, total: 3, soonestRetryAfterMs: 0 }, }); assert.equal(out?.targets[0].cooldownCount, undefined); assert.equal(out?.targets[0].cooldownTotal, undefined); assert.equal(out?.targets[0].cooldownRetryAfterMs, undefined); }); it("comboRunToFlow carries the cooldown fields into the target node data", () => { const run = mkRun([{ provider: "anthropic" }, { provider: "openai" }]); const enriched = enrichRunWithConnectionCooldown(run, { anthropic: { coolingDown: 1, total: 2, soonestRetryAfterMs: 12_000 }, }); const { nodes } = comboRunToFlow(enriched as ComboRunModel); const target0 = nodes.find((n) => n.id === "target-0"); assert.equal(target0?.data.cooldownCount, 1); assert.equal(target0?.data.cooldownTotal, 2); assert.equal(target0?.data.cooldownRetryAfterMs, 12_000); const target1 = nodes.find((n) => n.id === "target-1"); assert.equal(target1?.data.cooldownCount, undefined, "healthy provider node has no cooldown"); }); it("composes with enrichRunWithBreakers without clobbering cbState", async () => { const { enrichRunWithBreakers } = await import("../../../src/app/(dashboard)/dashboard/combos/live/comboFlowModel.ts"); const run = mkRun([{ provider: "anthropic" }]); const withBreaker = enrichRunWithBreakers(run, { anthropic: { state: "OPEN", retryAfterMs: 41_000 }, }); const both = enrichRunWithConnectionCooldown(withBreaker, { anthropic: { coolingDown: 1, total: 2, soonestRetryAfterMs: 5000 }, }); assert.equal(both?.targets[0].cbState, "OPEN", "breaker overlay survives the cooldown overlay"); assert.equal(both?.targets[0].cooldownCount, 1); }); });