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

132 lines
4.6 KiB
TypeScript

import { describe, it, beforeEach } from "node:test";
import assert from "node:assert/strict";
import { buildCacheKey, get, set, invalidate, stats } from "../../src/lib/memory/embedding/cache";
describe("memory-embedding-cache", () => {
beforeEach(() => {
invalidate();
});
it("returns undefined for unknown key", () => {
const result = get("nonexistent-key");
assert.strictEqual(result, undefined);
});
it("set + get returns the stored vector", () => {
const vec = new Float32Array([1.0, 2.0, 3.0]);
const key = buildCacheKey("remote", "openai/text-embedding-3-small", 3, "hello");
set(key, vec);
const retrieved = get(key);
assert.ok(retrieved instanceof Float32Array);
assert.strictEqual(retrieved.length, 3);
assert.strictEqual(retrieved[0], 1.0);
});
it("tracks hits and misses correctly", () => {
const key = buildCacheKey("static", "potion-base-8M", 256, "test");
const vec = new Float32Array([0.5, 0.6]);
set(key, vec);
get(key); // hit
get(key); // hit
get("missing"); // miss
get("missing2"); // miss
const s = stats();
assert.strictEqual(s.hits, 2);
assert.strictEqual(s.misses, 2);
assert.strictEqual(s.size, 1);
});
it("cache expires after TTL", () => {
// Override Date.now for TTL test via fake ts injection
const key = buildCacheKey("remote", "openai/text-embedding-3-small", 1536, "expire-test");
const vec = new Float32Array([9.0]);
// Inject the entry directly with an old timestamp via set + Date mock
const origNow = Date.now;
try {
// Set with very old timestamp by temporarily overriding Date.now
(Date as unknown as { now: () => number }).now = () => 0;
set(key, vec);
// Restore Date.now to "current" time = 6 minutes later (360000ms)
(Date as unknown as { now: () => number }).now = () => 360_000;
const result = get(key);
assert.strictEqual(result, undefined, "Expired entry should return undefined");
} finally {
(Date as unknown as { now: () => number }).now = origNow;
}
});
it("LRU eviction: when max=3 and 4th item inserted, oldest is removed", () => {
// Set MEMORY_EMBEDDING_CACHE_MAX to 3 via env
const origEnv = process.env.MEMORY_EMBEDDING_CACHE_MAX;
process.env.MEMORY_EMBEDDING_CACHE_MAX = "3";
invalidate();
try {
const k1 = buildCacheKey("remote", "model", null, "text1");
const k2 = buildCacheKey("remote", "model", null, "text2");
const k3 = buildCacheKey("remote", "model", null, "text3");
const k4 = buildCacheKey("remote", "model", null, "text4");
set(k1, new Float32Array([1]));
set(k2, new Float32Array([2]));
set(k3, new Float32Array([3]));
// All 3 keys should exist
assert.ok(get(k1) !== undefined);
assert.ok(get(k2) !== undefined);
assert.ok(get(k3) !== undefined);
invalidate(); // reset hit/miss counts
process.env.MEMORY_EMBEDDING_CACHE_MAX = "3";
set(k1, new Float32Array([1]));
set(k2, new Float32Array([2]));
set(k3, new Float32Array([3]));
// Insert 4th — should evict k1 (oldest)
set(k4, new Float32Array([4]));
const s = stats();
assert.strictEqual(s.size, 3);
// k4 should be present
assert.ok(get(k4) !== undefined);
} finally {
if (origEnv === undefined) delete process.env.MEMORY_EMBEDDING_CACHE_MAX;
else process.env.MEMORY_EMBEDDING_CACHE_MAX = origEnv;
invalidate();
}
});
it("buildCacheKey produces different keys for different sources", () => {
const key1 = buildCacheKey("remote", "model/a", 256, "hello");
const key2 = buildCacheKey("static", "model/a", 256, "hello");
assert.notStrictEqual(key1, key2);
});
it("buildCacheKey produces different keys for different models", () => {
const key1 = buildCacheKey("remote", "openai/small", 1536, "hello");
const key2 = buildCacheKey("remote", "openai/large", 3072, "hello");
assert.notStrictEqual(key1, key2);
});
it("buildCacheKey is deterministic", () => {
const k1 = buildCacheKey("remote", "openai/text-embedding-3-small", 1536, "deterministic test");
const k2 = buildCacheKey("remote", "openai/text-embedding-3-small", 1536, "deterministic test");
assert.strictEqual(k1, k2);
});
it("invalidate clears cache and resets counters", () => {
const key = buildCacheKey("remote", "m", 1, "text");
set(key, new Float32Array([1]));
get(key);
invalidate();
const s = stats();
assert.strictEqual(s.size, 0);
assert.strictEqual(s.hits, 0);
assert.strictEqual(s.misses, 0);
assert.strictEqual(get(key), undefined);
});
});