1import { assert, describe, it } from "@effect/vitest";
2
3import { cursorFetchRange, mergeCursorFetch } from "./accountCache.ts";
4import type { UsageRecord } from "@t3tools/provider-core/server/usage";
5
6const DAY_MS = 24 * 60 * 60 * 1000;
7
8const record = (timestampMs: number): UsageRecord => ({
9 provider: "cursor",
10 timestampMs,
11 model: "claude-fable-5",
12 sessionId: "conversation-1",
13 totals: {
14 uncachedInputTokens: 0,
15 cachedInputTokens: 0,
16 cacheCreationTokens: 0,
17 outputTokens: 1,
18 reasoningTokens: 0,
19 },
20 reportedCostUsd: null,
21 speed: "standard",
22 dedupeKey: `cursor-account:a:${timestampMs}:0`,
23});
24
25describe("cursorAccountCache", () => {
26 it("refetches everything once the cache no longer reaches the retention start", () => {
27 const cache = {
28 accountKey: "a",
29 sinceMs: 0,
30 untilMs: 10 * DAY_MS,
31 fetchedAtMs: 10 * DAY_MS,
32 records: [record(5 * DAY_MS)],
33 };
34 const nowMs = 100 * DAY_MS;
35 const range = cursorFetchRange(cache, 10 * DAY_MS, nowMs);
36 assert.deepStrictEqual(range, { sinceMs: 10 * DAY_MS, untilMs: nowMs });
37
38 const { cache: merged } = mergeCursorFetch(
39 cache,
40 "a",
41 range,
42 [record(50 * DAY_MS)],
43 nowMs,
44 10 * DAY_MS,
45 );
46 assert.deepStrictEqual(
47 merged.records.map((entry) => entry.timestampMs),
48 [50 * DAY_MS],
49 );
50 // Then only the newest edge.
51 assert.deepStrictEqual(cursorFetchRange(merged, 11 * DAY_MS, nowMs + DAY_MS), {
52 sinceMs: nowMs - 60 * 60 * 1000,
53 untilMs: nowMs + DAY_MS,
54 });
55 });
56
57 it("reports an edge that only confirms the cache as unchanged", () => {
58 const cache = {
59 accountKey: "a",
60 sinceMs: 0,
61 untilMs: 10 * DAY_MS,
62 fetchedAtMs: 10 * DAY_MS,
63 records: [record(DAY_MS), record(10 * DAY_MS)],
64 };
65 const range = cursorFetchRange(cache, 0, 11 * DAY_MS);
66 assert.isFalse(
67 mergeCursorFetch(cache, "a", range, [record(10 * DAY_MS)], 11 * DAY_MS, 0).changed,
68 );
69 assert.isTrue(
70 mergeCursorFetch(
71 cache,
72 "a",
73 range,
74 [record(10 * DAY_MS), record(10.5 * DAY_MS)],
75 11 * DAY_MS,
76 0,
77 ).changed,
78 );
79 });
80});