summaryrefslogtreecommitdiffhomepage
path: root/packages/cache-warming/src/pure.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cache-warming/src/pure.test.ts')
-rw-r--r--packages/cache-warming/src/pure.test.ts486
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",
+ });
+ });
});