Files
OmniRoute/tests/unit/batch-status-cache.test.ts
diegosouzapw c1952db4cb feat(cli-tools): add /api/cli-tools/all-statuses batch endpoint + mtime cache + DRY checkToolConfigStatus (plan 14 F2)
- Extract checkToolConfigStatus() from /api/cli-tools/status/route.ts → src/lib/cliTools/checkToolConfigStatus.ts (DRY, sentinel comment, optional configPathOverride for tests)
- Create batchStatusCache.ts singleton in-memory Map<toolId,{mtimeMs,result}> (getCached/setCached/invalidate/clearCache)
- Create /api/cli-tools/all-statuses GET route: auth via requireCliToolsAuth, iterates CLI_TOOLS, Promise.allSettled per tool, timeout 5s, mtime-based cache, endpoint extraction, lastConfiguredAt merge, buildErrorBody on error path
- Update /api/cli-tools/status/route.ts to import from new module (no behavior change)
- 27 unit tests (batch-status-cache + check-tool-config-status) + 8 integration tests (all-statuses-route) — all passing
2026-05-27 21:43:44 -03:00

117 lines
3.8 KiB
TypeScript

/**
* Unit tests for src/lib/cliTools/batchStatusCache.ts
*
* Pure in-memory logic — no I/O or module mocking needed.
*/
import test from "node:test";
import assert from "node:assert/strict";
import {
getCached,
setCached,
invalidate,
clearCache,
} from "../../src/lib/cliTools/batchStatusCache.ts";
import type { ToolBatchStatus } from "../../src/shared/types/cliBatchStatus.ts";
const makeStatus = (installed: boolean): ToolBatchStatus => ({
detection: { installed, runnable: installed },
config: { status: "configured" },
});
test.beforeEach(() => {
clearCache();
});
// ── getCached / setCached ─────────────────────────────────────────────────────
test("getCached returns null when cache is empty", () => {
const result = getCached("claude", 1234);
assert.equal(result, null);
});
test("setCached + getCached: hit when mtime matches", () => {
const status = makeStatus(true);
setCached("claude", 5000, status);
const result = getCached("claude", 5000);
assert.deepEqual(result, status);
});
test("getCached returns null when mtime differs (cache miss)", () => {
const status = makeStatus(true);
setCached("claude", 5000, status);
const result = getCached("claude", 9999); // different mtime
assert.equal(result, null);
});
test("getCached returns null when mtime is 0 and stored mtime is nonzero", () => {
setCached("codex", 1000, makeStatus(false));
const result = getCached("codex", 0);
assert.equal(result, null);
});
test("getCached returns entry when mtime is 0 and stored mtime is also 0", () => {
const status = makeStatus(false);
setCached("codex", 0, status);
const result = getCached("codex", 0);
assert.deepEqual(result, status);
});
// ── invalidate ────────────────────────────────────────────────────────────────
test("invalidate removes entry from cache", () => {
setCached("droid", 1000, makeStatus(true));
invalidate("droid");
const result = getCached("droid", 1000);
assert.equal(result, null);
});
test("invalidate on nonexistent key does not throw", () => {
assert.doesNotThrow(() => invalidate("nonexistent-tool-id"));
});
// ── clearCache ────────────────────────────────────────────────────────────────
test("clearCache removes all entries", () => {
setCached("claude", 100, makeStatus(true));
setCached("codex", 200, makeStatus(false));
setCached("cline", 300, makeStatus(true));
clearCache();
assert.equal(getCached("claude", 100), null);
assert.equal(getCached("codex", 200), null);
assert.equal(getCached("cline", 300), null);
});
test("clearCache on empty cache does not throw", () => {
assert.doesNotThrow(() => clearCache());
});
// ── Multiple tools coexist ────────────────────────────────────────────────────
test("multiple tools can be cached independently", () => {
const statusA = makeStatus(true);
const statusB = makeStatus(false);
setCached("claude", 1000, statusA);
setCached("codex", 2000, statusB);
assert.deepEqual(getCached("claude", 1000), statusA);
assert.deepEqual(getCached("codex", 2000), statusB);
assert.equal(getCached("claude", 2000), null); // wrong mtime for claude
});
test("overwriting same toolId updates cached result", () => {
const first = makeStatus(true);
const second = makeStatus(false);
setCached("kilo", 5000, first);
setCached("kilo", 5000, second); // overwrite
const result = getCached("kilo", 5000);
assert.deepEqual(result, second);
});