diff options
Diffstat (limited to 'packages/cache-warming/src/pure.test.ts')
| -rw-r--r-- | packages/cache-warming/src/pure.test.ts | 486 |
1 files changed, 243 insertions, 243 deletions
diff --git a/packages/cache-warming/src/pure.test.ts b/packages/cache-warming/src/pure.test.ts index 357fcb9..02adaf7 100644 --- a/packages/cache-warming/src/pure.test.ts +++ b/packages/cache-warming/src/pure.test.ts @@ -1,297 +1,297 @@ import { describe, expect, it } from "vitest"; import type { ConversationState } from "./pure.js"; import { - buildConversationSpec, - buildDefaultSpec, - computeCachePct, - computeExpectedCacheRate, - isTokenCurrent, - MIN_INTERVAL_MS, - msToSeconds, - parseIntervalPayload, - parseSettings, - secondsToMs, - serializeSettings, - shouldWarm, + buildConversationSpec, + buildDefaultSpec, + computeCachePct, + computeExpectedCacheRate, + isTokenCurrent, + MIN_INTERVAL_MS, + msToSeconds, + parseIntervalPayload, + parseSettings, + secondsToMs, + serializeSettings, + shouldWarm, } from "./pure.js"; describe("computeCachePct", () => { - it("cacheRead/input rounded and clamped to 0..100", () => { - expect(computeCachePct(1000, 800)).toBe(80); - expect(computeCachePct(1000, 1200)).toBe(100); - expect(computeCachePct(1000, -100)).toBe(0); - expect(computeCachePct(1000, 0)).toBe(0); - expect(computeCachePct(1000, 333)).toBe(33); - }); + it("cacheRead/input rounded and clamped to 0..100", () => { + expect(computeCachePct(1000, 800)).toBe(80); + expect(computeCachePct(1000, 1200)).toBe(100); + expect(computeCachePct(1000, -100)).toBe(0); + expect(computeCachePct(1000, 0)).toBe(0); + expect(computeCachePct(1000, 333)).toBe(33); + }); - it("zero input tokens → 0", () => { - expect(computeCachePct(0, 500)).toBe(0); - expect(computeCachePct(-1, 500)).toBe(0); - }); + it("zero input tokens → 0", () => { + expect(computeCachePct(0, 500)).toBe(0); + expect(computeCachePct(-1, 500)).toBe(0); + }); }); describe("computeExpectedCacheRate", () => { - it("cacheRead/(cacheRead+cacheWrite) rounded", () => { - expect(computeExpectedCacheRate(800, 200)).toBe(80); - expect(computeExpectedCacheRate(500, 500)).toBe(50); - expect(computeExpectedCacheRate(1000, 0)).toBe(100); - expect(computeExpectedCacheRate(0, 1000)).toBe(0); - expect(computeExpectedCacheRate(333, 667)).toBe(33); - }); + it("cacheRead/(cacheRead+cacheWrite) rounded", () => { + expect(computeExpectedCacheRate(800, 200)).toBe(80); + expect(computeExpectedCacheRate(500, 500)).toBe(50); + expect(computeExpectedCacheRate(1000, 0)).toBe(100); + expect(computeExpectedCacheRate(0, 1000)).toBe(0); + expect(computeExpectedCacheRate(333, 667)).toBe(33); + }); - it("0 when cacheRead+cacheWrite is 0", () => { - expect(computeExpectedCacheRate(0, 0)).toBe(0); - }); + it("0 when cacheRead+cacheWrite is 0", () => { + expect(computeExpectedCacheRate(0, 0)).toBe(0); + }); }); describe("shouldWarm", () => { - it("returns true when enabled, idle, and token matches", () => { - const state: ConversationState = { - enabled: true, - intervalMs: 240_000, - active: false, - lastPct: null, - lastExpectedPct: null, - lastWarmAt: null, - nextWarmAt: null, - token: 5, - }; - expect(shouldWarm(state, 5)).toBe(true); - }); + it("returns true when enabled, idle, and token matches", () => { + const state: ConversationState = { + enabled: true, + intervalMs: 240_000, + active: false, + lastPct: null, + lastExpectedPct: null, + lastWarmAt: null, + nextWarmAt: null, + token: 5, + }; + expect(shouldWarm(state, 5)).toBe(true); + }); - it("returns false when disabled", () => { - const state: ConversationState = { - enabled: false, - intervalMs: 240_000, - active: false, - lastPct: null, - lastExpectedPct: null, - lastWarmAt: null, - nextWarmAt: null, - token: 5, - }; - expect(shouldWarm(state, 5)).toBe(false); - }); + it("returns false when disabled", () => { + const state: ConversationState = { + enabled: false, + intervalMs: 240_000, + active: false, + lastPct: null, + lastExpectedPct: null, + lastWarmAt: null, + nextWarmAt: null, + token: 5, + }; + expect(shouldWarm(state, 5)).toBe(false); + }); - it("returns false when active", () => { - const state: ConversationState = { - enabled: true, - intervalMs: 240_000, - active: true, - lastPct: null, - lastExpectedPct: null, - lastWarmAt: null, - nextWarmAt: null, - token: 5, - }; - expect(shouldWarm(state, 5)).toBe(false); - }); + it("returns false when active", () => { + const state: ConversationState = { + enabled: true, + intervalMs: 240_000, + active: true, + lastPct: null, + lastExpectedPct: null, + lastWarmAt: null, + nextWarmAt: null, + token: 5, + }; + expect(shouldWarm(state, 5)).toBe(false); + }); - it("returns false when token is superseded", () => { - const state: ConversationState = { - enabled: true, - intervalMs: 240_000, - active: false, - lastPct: null, - lastExpectedPct: null, - lastWarmAt: null, - nextWarmAt: null, - token: 5, - }; - expect(shouldWarm(state, 6)).toBe(false); - }); + it("returns false when token is superseded", () => { + const state: ConversationState = { + enabled: true, + intervalMs: 240_000, + active: false, + lastPct: null, + lastExpectedPct: null, + lastWarmAt: null, + nextWarmAt: null, + token: 5, + }; + expect(shouldWarm(state, 6)).toBe(false); + }); }); describe("isTokenCurrent", () => { - it("returns true when tokens match", () => { - expect(isTokenCurrent(5, 5)).toBe(true); - }); + it("returns true when tokens match", () => { + expect(isTokenCurrent(5, 5)).toBe(true); + }); - it("returns false when tokens differ", () => { - expect(isTokenCurrent(5, 6)).toBe(false); - }); + it("returns false when tokens differ", () => { + expect(isTokenCurrent(5, 6)).toBe(false); + }); }); describe("parseSettings/serializeSettings round-trip", () => { - it("round-trips enabled + intervalMs", () => { - const original = { enabled: false, intervalMs: 120_000 }; - const serialized = serializeSettings(original); - const parsed = parseSettings(serialized); - expect(parsed).toEqual(original); - }); + it("round-trips enabled + intervalMs", () => { + const original = { enabled: false, intervalMs: 120_000 }; + const serialized = serializeSettings(original); + const parsed = parseSettings(serialized); + expect(parsed).toEqual(original); + }); - it("returns defaults for null input (warming OFF by default — CR-4a)", () => { - const parsed = parseSettings(null); - expect(parsed).toEqual({ enabled: false, intervalMs: 240_000 }); - }); + it("returns defaults for null input (warming OFF by default — CR-4a)", () => { + const parsed = parseSettings(null); + expect(parsed).toEqual({ enabled: false, intervalMs: 240_000 }); + }); - it("returns defaults for malformed JSON (warming OFF by default — CR-4a)", () => { - const parsed = parseSettings("not-json{{{"); - expect(parsed).toEqual({ enabled: false, intervalMs: 240_000 }); - }); + it("returns defaults for malformed JSON (warming OFF by default — CR-4a)", () => { + const parsed = parseSettings("not-json{{{"); + expect(parsed).toEqual({ enabled: false, intervalMs: 240_000 }); + }); - it("clamps non-positive interval to MIN_INTERVAL_MS", () => { - const parsed = parseSettings(JSON.stringify({ enabled: true, intervalMs: -500 })); - expect(parsed.intervalMs).toBe(1000); - }); + it("clamps non-positive interval to MIN_INTERVAL_MS", () => { + const parsed = parseSettings(JSON.stringify({ enabled: true, intervalMs: -500 })); + expect(parsed.intervalMs).toBe(1000); + }); - it("uses default for NaN interval", () => { - const parsed = parseSettings(JSON.stringify({ enabled: true, intervalMs: Number.NaN })); - expect(parsed.intervalMs).toBe(240_000); - }); + it("uses default for NaN interval", () => { + const parsed = parseSettings(JSON.stringify({ enabled: true, intervalMs: Number.NaN })); + expect(parsed.intervalMs).toBe(240_000); + }); }); describe("msToSeconds", () => { - it("converts ms to seconds, rounded", () => { - expect(msToSeconds(240_000)).toBe(240); - expect(msToSeconds(1500)).toBe(2); - expect(msToSeconds(1000)).toBe(1); - expect(msToSeconds(0)).toBe(0); - }); + it("converts ms to seconds, rounded", () => { + expect(msToSeconds(240_000)).toBe(240); + expect(msToSeconds(1500)).toBe(2); + expect(msToSeconds(1000)).toBe(1); + expect(msToSeconds(0)).toBe(0); + }); }); describe("secondsToMs", () => { - it("converts seconds to ms, floors at MIN_INTERVAL_MS", () => { - expect(secondsToMs(240)).toBe(240_000); - expect(secondsToMs(1)).toBe(1000); - expect(secondsToMs(0.5)).toBe(MIN_INTERVAL_MS); - }); + it("converts seconds to ms, floors at MIN_INTERVAL_MS", () => { + expect(secondsToMs(240)).toBe(240_000); + expect(secondsToMs(1)).toBe(1000); + expect(secondsToMs(0.5)).toBe(MIN_INTERVAL_MS); + }); - it("returns null for NaN / non-positive", () => { - expect(secondsToMs(Number.NaN)).toBeNull(); - expect(secondsToMs(0)).toBeNull(); - expect(secondsToMs(-5)).toBeNull(); - expect(secondsToMs(Number.POSITIVE_INFINITY)).toBeNull(); - }); + it("returns null for NaN / non-positive", () => { + expect(secondsToMs(Number.NaN)).toBeNull(); + expect(secondsToMs(0)).toBeNull(); + expect(secondsToMs(-5)).toBeNull(); + expect(secondsToMs(Number.POSITIVE_INFINITY)).toBeNull(); + }); }); describe("parseIntervalPayload", () => { - it("accepts a bare positive number", () => { - expect(parseIntervalPayload(30)).toBe(30); - expect(parseIntervalPayload(1)).toBe(1); - }); + it("accepts a bare positive number", () => { + expect(parseIntervalPayload(30)).toBe(30); + expect(parseIntervalPayload(1)).toBe(1); + }); - it("accepts { value: number }", () => { - expect(parseIntervalPayload({ value: 30 })).toBe(30); - expect(parseIntervalPayload({ value: 1 })).toBe(1); - }); + it("accepts { value: number }", () => { + expect(parseIntervalPayload({ value: 30 })).toBe(30); + expect(parseIntervalPayload({ value: 1 })).toBe(1); + }); - it("returns null for NaN / non-positive / wrong shape", () => { - expect(parseIntervalPayload(Number.NaN)).toBeNull(); - expect(parseIntervalPayload(0)).toBeNull(); - expect(parseIntervalPayload(-5)).toBeNull(); - expect(parseIntervalPayload("30")).toBeNull(); - expect(parseIntervalPayload({ value: "30" })).toBeNull(); - expect(parseIntervalPayload({})).toBeNull(); - expect(parseIntervalPayload(null)).toBeNull(); - expect(parseIntervalPayload(undefined)).toBeNull(); - }); + it("returns null for NaN / non-positive / wrong shape", () => { + expect(parseIntervalPayload(Number.NaN)).toBeNull(); + expect(parseIntervalPayload(0)).toBeNull(); + expect(parseIntervalPayload(-5)).toBeNull(); + expect(parseIntervalPayload("30")).toBeNull(); + expect(parseIntervalPayload({ value: "30" })).toBeNull(); + expect(parseIntervalPayload({})).toBeNull(); + expect(parseIntervalPayload(null)).toBeNull(); + expect(parseIntervalPayload(undefined)).toBeNull(); + }); }); describe("buildConversationSpec", () => { - it("builds a per-conversation spec with toggle + number(interval) + last-% + retention + timer fields", () => { - const spec = buildConversationSpec(true, 240_000, 80, 95, 1000, 500); - expect(spec.id).toBe("cache-warming"); - expect(spec.region).toBe("side"); - expect(spec.title).toBe("Cache Warming"); - expect(spec.fields).toHaveLength(5); + it("builds a per-conversation spec with toggle + number(interval) + last-% + retention + timer fields", () => { + const spec = buildConversationSpec(true, 240_000, 80, 95, 1000, 500); + expect(spec.id).toBe("cache-warming"); + expect(spec.region).toBe("side"); + expect(spec.title).toBe("Cache Warming"); + expect(spec.fields).toHaveLength(5); - const toggle = spec.fields[0]; - expect(toggle).toEqual({ - kind: "toggle", - label: "Enabled", - value: true, - action: { actionId: "cache-warming/toggle" }, - }); + const toggle = spec.fields[0]; + expect(toggle).toEqual({ + kind: "toggle", + label: "Enabled", + value: true, + action: { actionId: "cache-warming/toggle" }, + }); - const number = spec.fields[1]; - expect(number).toEqual({ - kind: "number", - label: "Refresh Interval", - value: 240, - min: 1, - step: 1, - unit: "s", - action: { actionId: "cache-warming/set-interval" }, - }); + const number = spec.fields[1]; + expect(number).toEqual({ + kind: "number", + label: "Refresh Interval", + value: 240, + min: 1, + step: 1, + unit: "s", + action: { actionId: "cache-warming/set-interval" }, + }); - const stat = spec.fields[2]; - expect(stat).toEqual({ - kind: "stat", - label: "Last Cache %", - value: "80%", - }); + const stat = spec.fields[2]; + expect(stat).toEqual({ + kind: "stat", + label: "Last Cache %", + value: "80%", + }); - const retention = spec.fields[3]; - expect(retention).toEqual({ - kind: "stat", - label: "Cache retention", - value: "95%", - }); + const retention = spec.fields[3]; + expect(retention).toEqual({ + kind: "stat", + label: "Cache retention", + value: "95%", + }); - const timer = spec.fields[4]; - expect(timer).toEqual({ - kind: "custom", - rendererId: "cache-warming-timer", - payload: { nextWarmAt: 1000, lastWarmAt: 500 }, - }); - }); + const timer = spec.fields[4]; + expect(timer).toEqual({ + kind: "custom", + rendererId: "cache-warming-timer", + payload: { nextWarmAt: 1000, lastWarmAt: 500 }, + }); + }); - it("shows — when lastPct and lastExpectedPct are null", () => { - const spec = buildConversationSpec(true, 240_000, null, null, null, null); - const stat = spec.fields[2]; - expect(stat).toEqual({ - kind: "stat", - label: "Last Cache %", - value: "—", - }); - const retention = spec.fields[3]; - expect(retention).toEqual({ - kind: "stat", - label: "Cache retention", - value: "—", - }); - const timer = spec.fields[4]; - expect(timer).toEqual({ - kind: "custom", - rendererId: "cache-warming-timer", - payload: { nextWarmAt: null, lastWarmAt: null }, - }); - }); + it("shows — when lastPct and lastExpectedPct are null", () => { + const spec = buildConversationSpec(true, 240_000, null, null, null, null); + const stat = spec.fields[2]; + expect(stat).toEqual({ + kind: "stat", + label: "Last Cache %", + value: "—", + }); + const retention = spec.fields[3]; + expect(retention).toEqual({ + kind: "stat", + label: "Cache retention", + value: "—", + }); + const timer = spec.fields[4]; + expect(timer).toEqual({ + kind: "custom", + rendererId: "cache-warming-timer", + payload: { nextWarmAt: null, lastWarmAt: null }, + }); + }); - it("reflects disabled state", () => { - const spec = buildConversationSpec(false, 120_000, 50, 75, null, null); - const toggle = spec.fields[0]; - expect(toggle).toEqual({ - kind: "toggle", - label: "Enabled", - value: false, - action: { actionId: "cache-warming/toggle" }, - }); - const number = spec.fields[1]; - expect(number).toEqual({ - kind: "number", - label: "Refresh Interval", - value: 120, - min: 1, - step: 1, - unit: "s", - action: { actionId: "cache-warming/set-interval" }, - }); - }); + it("reflects disabled state", () => { + const spec = buildConversationSpec(false, 120_000, 50, 75, null, null); + const toggle = spec.fields[0]; + expect(toggle).toEqual({ + kind: "toggle", + label: "Enabled", + value: false, + action: { actionId: "cache-warming/toggle" }, + }); + const number = spec.fields[1]; + expect(number).toEqual({ + kind: "number", + label: "Refresh Interval", + value: 120, + min: 1, + step: 1, + unit: "s", + action: { actionId: "cache-warming/set-interval" }, + }); + }); }); describe("buildDefaultSpec", () => { - it("returns a default spec with no conversationId", () => { - const spec = buildDefaultSpec(); - expect(spec.id).toBe("cache-warming"); - expect(spec.region).toBe("side"); - expect(spec.title).toBe("Cache Warming"); - expect(spec.fields).toHaveLength(1); - expect(spec.fields[0]).toEqual({ - kind: "stat", - label: "Status", - value: "No conversation focused", - }); - }); + it("returns a default spec with no conversationId", () => { + const spec = buildDefaultSpec(); + expect(spec.id).toBe("cache-warming"); + expect(spec.region).toBe("side"); + expect(spec.title).toBe("Cache Warming"); + expect(spec.fields).toHaveLength(1); + expect(spec.fields[0]).toEqual({ + kind: "stat", + label: "Status", + value: "No conversation focused", + }); + }); }); |
