Skip to content

Commit 00cb426

Browse files
committed
test: strengthen LRU eviction test with key-level assertions
Add hasCronInCacheForTest helper and assert specific cache entries survive or get evicted. The test now fails under FIFO but passes under LRU, directly verifying the promotion behavior.
1 parent a2dd5c5 commit 00cb426

2 files changed

Lines changed: 19 additions & 8 deletions

File tree

src/cron/schedule.test.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
computeNextRunAtMs,
66
computePreviousRunAtMs,
77
getCronScheduleCacheSizeForTest,
8+
hasCronInCacheForTest,
89
} from "./schedule.js";
910

1011
describe("cron schedule", () => {
@@ -147,7 +148,8 @@ describe("cron schedule", () => {
147148
it("promotes accessed entries to avoid premature LRU eviction", () => {
148149
const nowMs = Date.parse("2026-03-01T00:00:00.000Z");
149150

150-
// Fill cache to capacity with unique expressions
151+
// Fill cache to capacity with unique expressions.
152+
// i=0 → "0 0 * * *", i=1 → "1 0 * * *", ..., i=511 → "31 8 * * *"
151153
for (let i = 0; i < 512; i++) {
152154
computeNextRunAtMs(
153155
{ kind: "cron", expr: `${i % 60} ${Math.floor(i / 60)} * * *`, tz: "UTC" },
@@ -156,18 +158,23 @@ describe("cron schedule", () => {
156158
}
157159
expect(getCronScheduleCacheSizeForTest()).toBe(512);
158160

159-
// Access the very first entry so it gets promoted (LRU touch)
161+
// Entry #0 ("0 0 * * *") is the oldest by insertion order.
162+
// Access it so LRU promotes it (delete + re-insert at end of Map).
160163
computeNextRunAtMs({ kind: "cron", expr: "0 0 * * *", tz: "UTC" }, nowMs);
161164

162-
// Insert a new entry — this should evict the second-oldest, not the first
165+
// Entry #1 ("1 0 * * *") is now the least-recently-used.
166+
// Insert a new entry to trigger one eviction.
163167
computeNextRunAtMs({ kind: "cron", expr: "0 0 1 1 *", tz: "UTC" }, nowMs);
164168
expect(getCronScheduleCacheSizeForTest()).toBe(512);
165169

166-
// The first entry should still be cached (was promoted).
167-
// Insert another new entry — if FIFO, the first entry would now be evicted.
168-
// With LRU, the third-oldest entry is evicted instead.
169-
computeNextRunAtMs({ kind: "cron", expr: "0 0 2 1 *", tz: "UTC" }, nowMs);
170-
expect(getCronScheduleCacheSizeForTest()).toBe(512);
170+
// Under LRU: entry #0 survived (was promoted), entry #1 was evicted.
171+
// Under FIFO: entry #0 would be evicted instead — this assertion would fail.
172+
expect(hasCronInCacheForTest("0 0 * * *", "UTC")).toBe(true);
173+
expect(hasCronInCacheForTest("1 0 * * *", "UTC")).toBe(false);
174+
175+
// The new entry and a non-evicted middle entry should both be present.
176+
expect(hasCronInCacheForTest("0 0 1 1 *", "UTC")).toBe(true);
177+
expect(hasCronInCacheForTest("2 0 * * *", "UTC")).toBe(true);
171178
});
172179

173180
describe("cron with specific seconds (6-field pattern)", () => {

src/cron/schedule.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,7 @@ export function clearCronScheduleCacheForTest(): void {
171171
export function getCronScheduleCacheSizeForTest(): number {
172172
return cronEvalCache.size;
173173
}
174+
175+
export function hasCronInCacheForTest(expr: string, tz: string): boolean {
176+
return cronEvalCache.has(`${tz}\u0000${expr}`);
177+
}

0 commit comments

Comments
 (0)