singularity-forge/packages/pi-coding-agent/src/core/discovery-cache.test.ts
Iouri Goussev e0011a897a test: replace shape-only assertions with value checks (#1875)
Several test files used assert.ok(Array.isArray(x)) or assert.ok(result)
patterns that verify structure/existence without checking actual values.
These pass even when the code returns wrong data.

- web-diagnostics-contract: Array.isArray() checks → deepEqual([], [])
  for fields constructed as empty; DoctorFixResult uses deepEqual(["fix1"])
  instead of Array.isArray + length; InstanceType<typeof GSDWorkspaceStore>
  for type assertions from dynamic import
- skill-lifecycle: computeStaleAvoidList → deepEqual(result, []) since
  nonexistent path must return empty
- blob-store: remove redundant assert.ok(retrieved) before deepEqual
- discovery-cache: assert.ok(entry) existence check → verify models[0].id

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 15:25:10 -06:00

172 lines
5.6 KiB
TypeScript

import assert from "node:assert/strict";
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, beforeEach, describe, it } from "node:test";
import { ModelDiscoveryCache } from "./discovery-cache.js";
let testDir: string;
let cachePath: string;
beforeEach(() => {
testDir = join(tmpdir(), `discovery-cache-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
mkdirSync(testDir, { recursive: true });
cachePath = join(testDir, "discovery-cache.json");
});
afterEach(() => {
try {
rmSync(testDir, { recursive: true, force: true });
} catch {
// Cleanup best-effort
}
});
// ─── basic operations ────────────────────────────────────────────────────────
describe("ModelDiscoveryCache — basic operations", () => {
it("starts with no entries", () => {
const cache = new ModelDiscoveryCache(cachePath);
assert.equal(cache.get("openai"), undefined);
});
it("stores and retrieves models", () => {
const cache = new ModelDiscoveryCache(cachePath);
const models = [{ id: "gpt-4o", name: "GPT-4o" }];
cache.set("openai", models);
const entry = cache.get("openai");
assert.ok(entry);
assert.deepEqual(entry.models, models);
assert.ok(entry.fetchedAt > 0);
assert.ok(entry.ttlMs > 0);
});
it("persists to disk and reloads", () => {
const cache1 = new ModelDiscoveryCache(cachePath);
cache1.set("openai", [{ id: "gpt-4o" }]);
const cache2 = new ModelDiscoveryCache(cachePath);
const entry = cache2.get("openai");
assert.ok(entry);
assert.equal(entry.models[0].id, "gpt-4o");
});
it("clear removes a specific provider", () => {
const cache = new ModelDiscoveryCache(cachePath);
cache.set("openai", [{ id: "gpt-4o" }]);
cache.set("google", [{ id: "gemini-pro" }]);
cache.clear("openai");
assert.equal(cache.get("openai"), undefined);
const googleEntry = cache.get("google");
assert.ok(googleEntry);
assert.equal(googleEntry.models[0].id, "gemini-pro");
});
it("clear without provider removes all entries", () => {
const cache = new ModelDiscoveryCache(cachePath);
cache.set("openai", [{ id: "gpt-4o" }]);
cache.set("google", [{ id: "gemini-pro" }]);
cache.clear();
assert.equal(cache.get("openai"), undefined);
assert.equal(cache.get("google"), undefined);
});
});
// ─── staleness ───────────────────────────────────────────────────────────────
describe("ModelDiscoveryCache — staleness", () => {
it("newly set entries are not stale", () => {
const cache = new ModelDiscoveryCache(cachePath);
cache.set("openai", [{ id: "gpt-4o" }]);
assert.equal(cache.isStale("openai"), false);
});
it("missing providers are stale", () => {
const cache = new ModelDiscoveryCache(cachePath);
assert.equal(cache.isStale("unknown"), true);
});
it("entries with expired TTL are stale", () => {
const cache = new ModelDiscoveryCache(cachePath);
cache.set("openai", [{ id: "gpt-4o" }], 1); // 1ms TTL
// Wait for TTL to expire
const start = Date.now();
while (Date.now() - start < 5) {
// busy wait
}
assert.equal(cache.isStale("openai"), true);
});
});
// ─── getAll ──────────────────────────────────────────────────────────────────
describe("ModelDiscoveryCache — getAll", () => {
it("returns non-stale entries by default", () => {
const cache = new ModelDiscoveryCache(cachePath);
cache.set("openai", [{ id: "gpt-4o" }]);
cache.set("stale", [{ id: "old" }], 1);
// Wait for stale TTL
const start = Date.now();
while (Date.now() - start < 5) {
// busy wait
}
const all = cache.getAll();
assert.ok(all.has("openai"));
assert.ok(!all.has("stale"));
});
it("returns all entries when includeStale is true", () => {
const cache = new ModelDiscoveryCache(cachePath);
cache.set("openai", [{ id: "gpt-4o" }]);
cache.set("stale", [{ id: "old" }], 1);
// Wait for stale TTL
const start = Date.now();
while (Date.now() - start < 5) {
// busy wait
}
const all = cache.getAll(true);
assert.ok(all.has("openai"));
assert.ok(all.has("stale"));
});
});
// ─── edge cases ──────────────────────────────────────────────────────────────
describe("ModelDiscoveryCache — edge cases", () => {
it("handles corrupted cache file gracefully", () => {
writeFileSync(cachePath, "not valid json", "utf-8");
const cache = new ModelDiscoveryCache(cachePath);
assert.equal(cache.get("openai"), undefined);
});
it("handles wrong version gracefully", () => {
writeFileSync(cachePath, JSON.stringify({ version: 99, entries: {} }), "utf-8");
const cache = new ModelDiscoveryCache(cachePath);
assert.equal(cache.get("openai"), undefined);
});
it("handles missing cache file", () => {
const cache = new ModelDiscoveryCache(join(testDir, "nonexistent", "cache.json"));
assert.equal(cache.get("openai"), undefined);
});
it("overwrites existing entry for same provider", () => {
const cache = new ModelDiscoveryCache(cachePath);
cache.set("openai", [{ id: "gpt-4o" }]);
cache.set("openai", [{ id: "gpt-4o-mini" }]);
const entry = cache.get("openai");
assert.ok(entry);
assert.equal(entry.models.length, 1);
assert.equal(entry.models[0].id, "gpt-4o-mini");
});
});