import test from "node:test"; import assert from "node:assert/strict"; import { once } from "node:events"; import { loadConfig } from "../src/config.js"; import { createApp } from "../src/app.js"; // --------------------------------------------------------------------------- // Helpers: run the app on an ephemeral loopback port with an injected fetch, // so no Qdrant/Ollama needs to be up. // --------------------------------------------------------------------------- const TEST_ENV = { QDRANT_URL: "http://qdrant.test:6333", OLLAMA_URL: "http://ollama.test:11436", EMBED_MODEL: "nomic-embed-text", PROBE_TIMEOUT_MS: "200", UPSTREAM_TIMEOUT_MS: "500", }; async function withServer(fetchImpl, fn, envOverrides = {}) { const config = loadConfig({ ...TEST_ENV, ...envOverrides }); const app = createApp(config, { fetchImpl }); const server = app.listen(0, "127.0.0.1"); await once(server, "listening"); const base = `http://127.0.0.1:${server.address().port}`; try { return await fn(base, config); } finally { server.close(); } } function jsonResponse(body, status = 200) { return new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" }, }); } /** Fake fetch that dispatches on method+url via a routes table. */ function fakeFetch(routes) { const calls = []; const impl = async (url, init = {}) => { const method = init.method ?? "GET"; const key = `${method} ${url}`; calls.push({ key, url: String(url), method, body: init.body ? JSON.parse(init.body) : undefined }); for (const [pattern, handler] of Object.entries(routes)) { if (key === pattern || key.startsWith(pattern)) { return handler({ url, init, body: init.body ? JSON.parse(init.body) : undefined }); } } throw new TypeError(`fetch failed: no route for ${key}`); }; impl.calls = calls; return impl; } const DIM = 4; const vecFor = (text) => [text.length, 1, 2, 3]; function happyRoutes() { return { // health probes "GET http://qdrant.test:6333/readyz": () => new Response("all shards ready", { status: 200 }), "GET http://ollama.test:11436/api/tags": () => jsonResponse({ models: [{ name: "nomic-embed-text:latest" }, { name: "qwen3:30b-a3b" }] }), // embeddings "POST http://ollama.test:11436/api/embeddings": ({ body }) => jsonResponse({ embedding: vecFor(body.prompt) }), // qdrant collection lifecycle "GET http://qdrant.test:6333/collections/notes": () => jsonResponse({ result: {} }, 404), "PUT http://qdrant.test:6333/collections/notes/points": () => jsonResponse({ result: { operation_id: 1, status: "completed" } }), "PUT http://qdrant.test:6333/collections/notes": () => jsonResponse({ result: true }), "POST http://qdrant.test:6333/collections/notes/points/search": () => jsonResponse({ result: [ { id: "a", score: 0.91, payload: { text: "alpha", src: "t" } }, { id: "b", score: 0.42, payload: { text: "beta" } }, ], }), }; } // --------------------------------------------------------------------------- // config // --------------------------------------------------------------------------- test("config defaults: port 5499, qdrant 6333, ollama 11436 (NOT 11434), nomic-embed-text", () => { const c = loadConfig({}); assert.equal(c.port, 5499); assert.equal(c.qdrantUrl, "http://127.0.0.1:6333"); assert.equal(c.ollamaUrl, "http://127.0.0.1:11436"); assert.ok(!c.ollamaUrl.includes("11434"), "must never default to the broken 11434 forward"); assert.equal(c.embedModel, "nomic-embed-text"); }); // --------------------------------------------------------------------------- // /health — three-valued // --------------------------------------------------------------------------- test("/health reports ok with surfaces + observed_at when all deps respond", async () => { await withServer(fakeFetch(happyRoutes()), async (base) => { const res = await fetch(`${base}/health`); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.status, "ok"); assert.equal(body.dependencies.qdrant.status, "ok"); assert.equal(body.dependencies.qdrant.measurement_surface, "http://qdrant.test:6333/readyz"); assert.equal(body.dependencies.ollama.status, "ok"); assert.equal(body.dependencies.ollama.measurement_surface, "http://ollama.test:11436/api/tags"); assert.equal(body.dependencies.embed_model.status, "ok"); for (const dep of Object.values(body.dependencies)) { assert.ok(Date.parse(dep.observed_at), "every dep carries observed_at"); } }); }); test("/health reports unobservable (never healthy) when deps are down", async () => { // fetch that always fails = both dependencies down const deadFetch = async () => { throw new TypeError("fetch failed: ECONNREFUSED"); }; await withServer(deadFetch, async (base) => { const res = await fetch(`${base}/health`); assert.equal(res.status, 503); const body = await res.json(); assert.equal(body.status, "degraded"); assert.notEqual(body.status, "ok", "must never report plain healthy while a dep is unobservable"); assert.equal(body.dependencies.qdrant.status, "unobservable"); assert.match(body.dependencies.qdrant.reason, /fetch failed/); assert.equal(body.dependencies.ollama.status, "unobservable"); // model presence is ALSO unobservable — not "absent" — when ollama is down assert.equal(body.dependencies.embed_model.status, "unobservable"); assert.equal(body.dependencies.qdrant.measurement_surface, "http://qdrant.test:6333/readyz"); }); }); test("/health: dep returning HTTP 500 is unobservable, not ok and not absent", async () => { const routes = happyRoutes(); routes["GET http://qdrant.test:6333/readyz"] = () => new Response("boom", { status: 500 }); await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); assert.equal(res.status, 503); const body = await res.json(); assert.equal(body.status, "degraded"); assert.equal(body.dependencies.qdrant.status, "unobservable"); assert.equal(body.dependencies.qdrant.http_status, 500); assert.equal(body.dependencies.ollama.status, "ok"); }); }); test("/health: embed model missing from a REACHABLE ollama is absent (a true gap)", async () => { const routes = happyRoutes(); routes["GET http://ollama.test:11436/api/tags"] = () => jsonResponse({ models: [{ name: "qwen3:30b-a3b" }] }); await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); const body = await res.json(); assert.equal(body.dependencies.ollama.status, "ok", "ollama itself was observable"); assert.equal(body.dependencies.embed_model.status, "absent"); assert.equal(body.status, "degraded"); assert.equal(res.status, 503); }); }); test("/health: bare EMBED_MODEL matches installed tagged model (nomic-embed-text ~ :latest)", async () => { // happyRoutes lists nomic-embed-text:latest; config asks for bare name. await withServer(fakeFetch(happyRoutes()), async (base) => { const res = await fetch(`${base}/health`); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.dependencies.embed_model.status, "ok"); }); }); test("/health: tagged EMBED_MODEL matches installed bare model (reverse direction)", async () => { const routes = happyRoutes(); routes["GET http://ollama.test:11436/api/tags"] = () => jsonResponse({ models: [{ name: "nomic-embed-text" }] }); await withServer( fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.dependencies.embed_model.status, "ok"); }, { EMBED_MODEL: "nomic-embed-text:latest" } ); }); test("/health: when BOTH sides carry tags, tags must match exactly (mismatch => absent)", async () => { const routes = happyRoutes(); // lists nomic-embed-text:latest await withServer( fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); assert.equal(res.status, 503); const body = await res.json(); assert.equal(body.dependencies.ollama.status, "ok"); assert.equal(body.dependencies.embed_model.status, "absent"); }, { EMBED_MODEL: "nomic-embed-text:v1.5" } ); }); test("/health: a different model base name never matches (no false ok on shared tag)", async () => { const routes = happyRoutes(); routes["GET http://ollama.test:11436/api/tags"] = () => jsonResponse({ models: [{ name: "mxbai-embed-large:latest" }] }); await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); const body = await res.json(); assert.equal(body.dependencies.embed_model.status, "absent"); }); }); test("/health: 200 tags response WITHOUT a models array is unobservable, never absent", async () => { for (const wrongShape of [{}, { tags: [{ name: "nomic-embed-text" }] }, { models: "nope" }, null]) { const routes = happyRoutes(); routes["GET http://ollama.test:11436/api/tags"] = () => jsonResponse(wrongShape); await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); assert.equal(res.status, 503); const body = await res.json(); assert.equal(body.dependencies.ollama.status, "ok", "reachability verdict stays ok"); assert.equal( body.dependencies.embed_model.status, "unobservable", `shape ${JSON.stringify(wrongShape)} cannot prove absence` ); assert.notEqual(body.dependencies.embed_model.status, "absent"); assert.equal(body.status, "degraded"); }); } }); test("/health: models list with unreadable entries cannot prove absence (unobservable)", async () => { for (const badList of [ [{}], [{ model: "nomic-embed-text" }], // wrong field name [{ name: "qwen3:30b-a3b" }, { name: 42 }], // mixed: one unreadable entry ]) { const routes = happyRoutes(); routes["GET http://ollama.test:11436/api/tags"] = () => jsonResponse({ models: badList }); await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); const body = await res.json(); assert.equal( body.dependencies.embed_model.status, "unobservable", `list ${JSON.stringify(badList)} has unreadable entries and cannot prove absence` ); }); } }); test("/health: positive evidence stands even amid malformed sibling entries", async () => { const routes = happyRoutes(); routes["GET http://ollama.test:11436/api/tags"] = () => jsonResponse({ models: [{}, { name: "nomic-embed-text:latest" }] }); await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); const body = await res.json(); assert.equal(body.dependencies.embed_model.status, "ok"); }); }); test("/health: an empty models list IS readable and proves absence", async () => { const routes = happyRoutes(); routes["GET http://ollama.test:11436/api/tags"] = () => jsonResponse({ models: [] }); await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); const body = await res.json(); assert.equal(body.dependencies.embed_model.status, "absent"); }); }); test("/health: non-JSON 200 tags body is unobservable", async () => { const routes = happyRoutes(); routes["GET http://ollama.test:11436/api/tags"] = () => new Response("proxy error", { status: 200 }); await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/health`); assert.equal(res.status, 503); const body = await res.json(); assert.equal(body.dependencies.embed_model.status, "unobservable"); }); }); test("/health: top-level object carries its own observed_at", async () => { await withServer(fakeFetch(happyRoutes()), async (base) => { const res = await fetch(`${base}/health`); const body = await res.json(); assert.ok(Date.parse(body.observed_at), "top-level observed_at is a valid timestamp"); }); }); // --------------------------------------------------------------------------- // /v1/embed // --------------------------------------------------------------------------- test("POST /v1/embed returns one vector per text via ollama", async () => { const f = fakeFetch(happyRoutes()); await withServer(f, async (base) => { const res = await fetch(`${base}/v1/embed`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ texts: ["hello", "worlds!"] }), }); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.vectors.length, 2); assert.deepEqual(body.vectors[0], vecFor("hello")); assert.deepEqual(body.vectors[1], vecFor("worlds!")); assert.equal(body.measurement_surface, "http://ollama.test:11436/api/embeddings"); assert.ok(Date.parse(body.observed_at)); const embedCalls = f.calls.filter((c) => c.key.includes("/api/embeddings")); assert.equal(embedCalls.length, 2); assert.equal(embedCalls[0].body.model, "nomic-embed-text"); }); }); test("POST /v1/embed with ollama down returns 502 marked unobservable with surface", async () => { const deadFetch = async () => { throw new TypeError("fetch failed: ECONNREFUSED"); }; await withServer(deadFetch, async (base) => { const res = await fetch(`${base}/v1/embed`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ texts: ["hello"] }), }); assert.equal(res.status, 502); const body = await res.json(); assert.equal(body.status, "unobservable"); assert.equal(body.measurement_surface, "http://ollama.test:11436/api/embeddings"); assert.ok(Date.parse(body.observed_at)); }); }); test("POST /v1/embed validates body", async () => { await withServer(fakeFetch(happyRoutes()), async (base) => { for (const bad of [{}, { texts: [] }, { texts: "hello" }, { texts: [1, 2] }]) { const res = await fetch(`${base}/v1/embed`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(bad), }); assert.equal(res.status, 400); } }); }); // --------------------------------------------------------------------------- // /v1/index // --------------------------------------------------------------------------- test("POST /v1/index embeds, auto-creates missing collection, upserts points", async () => { const f = fakeFetch(happyRoutes()); await withServer(f, async (base) => { const res = await fetch(`${base}/v1/index`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ collection: "notes", items: [ { id: 1, text: "alpha", payload: { src: "t" } }, { id: 2, text: "beta" }, ], }), }); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.indexed, 2); assert.equal(body.collection, "notes"); // collection was created with the right vector size const create = f.calls.find((c) => c.key === "PUT http://qdrant.test:6333/collections/notes"); assert.ok(create, "collection create issued"); assert.equal(create.body.vectors.size, DIM); // points carried vectors and payload (text folded in) const upsert = f.calls.find((c) => c.key.startsWith("PUT http://qdrant.test:6333/collections/notes/points")); assert.equal(upsert.body.points.length, 2); assert.deepEqual(upsert.body.points[0].vector, vecFor("alpha")); assert.deepEqual(upsert.body.points[0].payload, { src: "t", text: "alpha" }); }); }); test("POST /v1/index with qdrant down returns 502 unobservable (never silently indexed:0)", async () => { const routes = happyRoutes(); const qdrantDead = ({ url }) => { throw new TypeError("fetch failed: ECONNREFUSED " + url); }; routes["GET http://qdrant.test:6333/collections/notes"] = qdrantDead; await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/v1/index`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ collection: "notes", items: [{ id: 1, text: "alpha" }] }), }); assert.equal(res.status, 502); const body = await res.json(); assert.equal(body.status, "unobservable"); assert.equal(body.measurement_surface, "http://qdrant.test:6333/collections/notes"); }); }); test("POST /v1/index reports a measurement_surface byte-exact with the URL actually fetched", async () => { const f = fakeFetch(happyRoutes()); await withServer(f, async (base) => { const res = await fetch(`${base}/v1/index`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ collection: "notes", items: [{ id: 1, text: "alpha" }] }), }); assert.equal(res.status, 200); const body = await res.json(); const upsertCall = f.calls.find((c) => c.method === "PUT" && c.url.includes("/points")); assert.ok(upsertCall, "upsert call was made"); assert.equal(body.measurement_surface, upsertCall.url, "surface must byte-match the fetched URL"); assert.equal(body.measurement_surface, "http://qdrant.test:6333/collections/notes/points?wait=true"); }); }); test("POST /v1/index surface stays byte-exact when the collection name needs URL-encoding", async () => { const f = fakeFetch({ ...happyRoutes(), // NOTE: the /points route must precede the bare collection route (startsWith matching). "GET http://qdrant.test:6333/collections/my%20notes": () => jsonResponse({ result: {} }, 404), "PUT http://qdrant.test:6333/collections/my%20notes/points?wait=true": () => jsonResponse({ result: { operation_id: 7, status: "completed" } }), "PUT http://qdrant.test:6333/collections/my%20notes": () => jsonResponse({ result: true }), }); await withServer(f, async (base) => { const res = await fetch(`${base}/v1/index`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ collection: "my notes", items: [{ id: 1, text: "alpha" }] }), }); assert.equal(res.status, 200); const body = await res.json(); const upsertCall = f.calls.find((c) => c.method === "PUT" && c.url.includes("/points")); assert.equal(body.measurement_surface, upsertCall.url); assert.equal(body.measurement_surface, "http://qdrant.test:6333/collections/my%20notes/points?wait=true"); }); }); // --------------------------------------------------------------------------- // /v1/search // --------------------------------------------------------------------------- test("POST /v1/search embeds the query and returns scored payloads", async () => { const f = fakeFetch(happyRoutes()); await withServer(f, async (base) => { const res = await fetch(`${base}/v1/search`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ collection: "notes", query: "find alpha", limit: 2 }), }); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.results.length, 2); assert.deepEqual(body.results[0], { id: "a", score: 0.91, payload: { text: "alpha", src: "t" } }); const search = f.calls.find((c) => c.key.startsWith("POST http://qdrant.test:6333/collections/notes/points/search")); assert.deepEqual(search.body.vector, vecFor("find alpha")); assert.equal(search.body.limit, 2); assert.equal(search.body.with_payload, true); }); }); test("POST /v1/search reports a measurement_surface byte-exact with the URL actually fetched", async () => { const f = fakeFetch(happyRoutes()); await withServer(f, async (base) => { const res = await fetch(`${base}/v1/search`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ collection: "notes", query: "find alpha" }), }); assert.equal(res.status, 200); const body = await res.json(); const searchCall = f.calls.find((c) => c.method === "POST" && c.url.includes("/points/search")); assert.ok(searchCall, "search call was made"); assert.equal(body.measurement_surface, searchCall.url, "surface must byte-match the fetched URL"); assert.equal(body.measurement_surface, "http://qdrant.test:6333/collections/notes/points/search"); }); }); test("POST /v1/search surface stays byte-exact when the collection name needs URL-encoding", async () => { const f = fakeFetch({ ...happyRoutes(), "POST http://qdrant.test:6333/collections/my%20notes/points/search": () => jsonResponse({ result: [{ id: "a", score: 0.5, payload: { text: "alpha" } }] }), }); await withServer(f, async (base) => { const res = await fetch(`${base}/v1/search`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ collection: "my notes", query: "alpha" }), }); assert.equal(res.status, 200); const body = await res.json(); const searchCall = f.calls.find((c) => c.method === "POST" && c.url.includes("/points/search")); assert.equal(body.measurement_surface, searchCall.url); assert.equal(body.measurement_surface, "http://qdrant.test:6333/collections/my%20notes/points/search"); }); }); test("POST /v1/embed reports a measurement_surface byte-exact with the URL actually fetched", async () => { const f = fakeFetch(happyRoutes()); await withServer(f, async (base) => { const res = await fetch(`${base}/v1/embed`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ texts: ["hello"] }), }); assert.equal(res.status, 200); const body = await res.json(); const embedCall = f.calls.find((c) => c.method === "POST" && c.url.includes("/api/embeddings")); assert.equal(body.measurement_surface, embedCall.url, "surface must byte-match the fetched URL"); }); }); test("POST /v1/search with qdrant down returns 502 unobservable — never an empty result set", async () => { const routes = happyRoutes(); routes["POST http://qdrant.test:6333/collections/notes/points/search"] = () => { throw new TypeError("fetch failed: ECONNREFUSED"); }; await withServer(fakeFetch(routes), async (base) => { const res = await fetch(`${base}/v1/search`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ collection: "notes", query: "anything" }), }); assert.equal(res.status, 502); const body = await res.json(); assert.equal(body.status, "unobservable"); assert.ok(!("results" in body), "an unobservable search must not look like an empty result"); }); });