Files
diegosouzapw--omniroute/tests/unit/search-cache-ttl-zero.test.ts
2026-07-13 13:39:12 +08:00

146 lines
5.4 KiB
TypeScript

/**
* Tests for searchCache.ts — getOrCoalesce with ttlMs=0 bypass.
*
* Verifies:
* 1. ttlMs=0 bypasses the cache lookup (no stale data returned)
* 2. ttlMs=0 bypasses inflight coalescing (each concurrent call gets its own fetch)
* 3. Both concurrent callers receive { cached: false }
* 4. hits counter is NOT incremented for ttlMs=0 calls
* 5. ttlMs>0 still coalesces concurrent calls correctly
* 6. ?? operator in route.ts: cacheTTLMs=0 is not treated as falsy
*/
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import {
getOrCoalesce,
computeCacheKey,
getCacheStats,
} from "../../open-sse/services/searchCache.ts";
// ── Helper ────────────────────────────────────────────────────────────────────
function makeKey(suffix = "") {
return computeCacheKey(`ttl-zero-test-${suffix}-${Date.now()}`, "test", "search", 10);
}
// ── Tests ─────────────────────────────────────────────────────────────────────
describe("getOrCoalesce — ttlMs=0 bypass", () => {
it("returns { cached: false } when ttlMs=0", async () => {
const key = makeKey("basic");
let callCount = 0;
const fetchFn = async () => {
callCount++;
return { result: "fresh" };
};
const result = await getOrCoalesce(key, 0, fetchFn);
assert.equal(result.cached, false, "cached flag must be false when ttlMs=0");
assert.deepEqual(result.data, { result: "fresh" });
assert.equal(callCount, 1);
});
it("does NOT coalesce concurrent calls when ttlMs=0 — each gets its own fetch", async () => {
const key = makeKey("concurrent");
let callCount = 0;
const fetchFn = async () => {
callCount++;
// Slight delay to ensure both calls overlap
await new Promise((r) => setTimeout(r, 5));
return { id: callCount };
};
// Launch two concurrent calls with the SAME key and ttlMs=0
const [r1, r2] = await Promise.all([
getOrCoalesce(key, 0, fetchFn),
getOrCoalesce(key, 0, fetchFn),
]);
// Both should be independent — fetchFn must have been called twice
assert.equal(callCount, 2, "fetchFn must be called independently for each ttlMs=0 caller");
assert.equal(r1.cached, false, "r1.cached must be false");
assert.equal(r2.cached, false, "r2.cached must be false");
});
it("does NOT increment hits counter for ttlMs=0 calls", async () => {
const key = makeKey("hits");
const before = getCacheStats().hits;
await getOrCoalesce(key, 0, async () => "data");
await getOrCoalesce(key, 0, async () => "data");
const after = getCacheStats();
assert.equal(after.hits, before, "hits must not increment for ttlMs=0 calls");
});
it("does NOT store result in cache when ttlMs=0 — subsequent call still fetches fresh", async () => {
const key = makeKey("no-store");
let callCount = 0;
const fetchFn = async () => {
callCount++;
return callCount;
};
await getOrCoalesce(key, 0, fetchFn);
const r2 = await getOrCoalesce(key, 0, fetchFn);
assert.equal(callCount, 2, "second call must also invoke fetchFn (not serve from cache)");
assert.equal(r2.data, 2);
assert.equal(r2.cached, false);
});
it("coalesces concurrent calls when ttlMs>0 (baseline sanity check)", async () => {
const key = makeKey("coalesce-positive");
let callCount = 0;
const fetchFn = async () => {
callCount++;
await new Promise((r) => setTimeout(r, 5));
return "shared";
};
// Both calls launched with same key and ttlMs>0 — should coalesce
const [r1, r2] = await Promise.all([
getOrCoalesce(key, 5000, fetchFn),
getOrCoalesce(key, 5000, fetchFn),
]);
assert.equal(
callCount,
1,
"fetchFn should be called exactly once when coalescing with ttlMs>0"
);
assert.equal(r1.data, "shared");
assert.equal(r2.data, "shared");
});
});
// ── ?? operator behaviour (mirrors route.ts fix: cacheTTLMs ?? defaultTTL) ──
describe("cacheTTLMs ?? default (route.ts fix)", () => {
it("cacheTTLMs=0 must NOT fall back to default when using ?? (nullish coalescing)", () => {
const DEFAULT_TTL = 5 * 60 * 1000;
// Old behaviour: `cacheTTLMs || DEFAULT_TTL` treats 0 as falsy → returns DEFAULT_TTL (WRONG)
const oldBehaviour = (cacheTTLMs) => cacheTTLMs || DEFAULT_TTL;
// New behaviour: `cacheTTLMs ?? DEFAULT_TTL` only falls back for null/undefined (CORRECT)
const newBehaviour = (cacheTTLMs) => cacheTTLMs ?? DEFAULT_TTL;
// With cacheTTLMs=0, old behaviour incorrectly returns DEFAULT_TTL
assert.equal(oldBehaviour(0), DEFAULT_TTL, "Sanity: old || behaviour treats 0 as falsy");
// With cacheTTLMs=0, new behaviour correctly returns 0
assert.equal(newBehaviour(0), 0, "?? must preserve 0 as a valid TTL");
// null/undefined still correctly fall back to DEFAULT_TTL in both
assert.equal(newBehaviour(null), DEFAULT_TTL, "null must fall back to DEFAULT_TTL");
assert.equal(newBehaviour(undefined), DEFAULT_TTL, "undefined must fall back to DEFAULT_TTL");
// Positive TTL is unaffected
assert.equal(newBehaviour(1000), 1000, "positive TTL must not be affected");
});
});