import { test, expect, beforeEach, afterEach } from "vitest";
import {
getOrBuildRegistry,
clearRegistryCache,
setRegistryCacheEnabled,
isRegistryCacheEnabled,
} from "../runtime/registry-cache.ts";
import type { KernelAppConfig } from "@warpgogol/werkstatt-shared/kernel";
import type { ModuleExport } from "@warpgogol/werkstatt-shared/kernel";
/*
Verify ADR-0022 process-lifetime registry cache behavior: cache hit on second call,
cache disabled by setRegistryCacheEnabled(false), and clearRegistryCache invalidation.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- Fixtures stay inline and minimal so each case states its own setup.
- ADR-0022: initial test for process-lifetime registry cache.
*/
// @ai-invariant fixtures must not couple to internals beyond the public surface under test
const mockModule: ModuleExport = {
name: "test-module",
version: "1.0.0",
declarations: [],
commands: [
{
name: "test.ping",
modulePath: "test",
description: "Test command",
scope: "workspace",
flags: {},
execute: async () => ({ exitCode: 0, ok: true, summary: "pong" }),
},
],
pipelines: [],
};
const mockConfig: KernelAppConfig = {
modules: [mockModule],
};
beforeEach(() => {
clearRegistryCache();
setRegistryCacheEnabled(true);
});
afterEach(() => {
clearRegistryCache();
setRegistryCacheEnabled(true);
});
test("getOrBuildRegistry returns the same instance on second call (cache hit)", async () => {
const first = await getOrBuildRegistry("test-key-1", mockConfig);
const second = await getOrBuildRegistry("test-key-1", mockConfig);
expect(second).toBe(first);
});
test("getOrBuildRegistry returns different instances for different cache keys", async () => {
const first = await getOrBuildRegistry("test-key-a", mockConfig);
const second = await getOrBuildRegistry("test-key-b", mockConfig);
expect(second).not.toBe(first);
});
test("setRegistryCacheEnabled(false) bypasses cache and builds fresh registry", async () => {
const first = await getOrBuildRegistry("test-key-2", mockConfig);
setRegistryCacheEnabled(false);
const second = await getOrBuildRegistry("test-key-2", mockConfig);
expect(second).not.toBe(first);
expect(isRegistryCacheEnabled()).toBe(false);
});
test("setRegistryCacheEnabled(false) clears existing cached entries", async () => {
await getOrBuildRegistry("test-key-3", mockConfig);
setRegistryCacheEnabled(false);
expect(isRegistryCacheEnabled()).toBe(false);
});
test("clearRegistryCache forces a fresh build on next call", async () => {
const first = await getOrBuildRegistry("test-key-4", mockConfig);
clearRegistryCache();
const second = await getOrBuildRegistry("test-key-4", mockConfig);
expect(second).not.toBe(first);
});
test("cached registry is functional — commands are registered", async () => {
const registry = await getOrBuildRegistry("test-key-5", mockConfig);
expect([...registry.commands.keys()]).toContain("test.ping");
expect(registry.commands.get("test.ping")?.description).toBe("Test command");
});
test("re-enabling cache after disable resumes caching", async () => {
setRegistryCacheEnabled(false);
const first = await getOrBuildRegistry("test-key-6", mockConfig);
setRegistryCacheEnabled(true);
const second = await getOrBuildRegistry("test-key-6", mockConfig);
const third = await getOrBuildRegistry("test-key-6", mockConfig);
expect(second).not.toBe(first);
expect(third).toBe(second);
});