SysDeck/klanker-gate/apps/gateway/main_test.ts

135 lines
4.5 KiB
TypeScript
Executable File

import { assert, assertEquals } from "@std/assert";
import { createHandler } from "./main.ts";
import { type AppContext, NullToolExecutor, VERSION } from "./context.ts";
import { ProviderManager } from "../../packages/providers/src/mod.ts";
import { Metrics } from "../../packages/telemetry/src/metrics.ts";
import { LogBus } from "../../packages/telemetry/src/logbus.ts";
import { VirtualKeyManager } from "../../packages/governance/src/virtual_keys.ts";
import { MCPRegistry } from "../../packages/mcp/src/registry.ts";
import { PluginManager } from "../../packages/plugins/src/lifecycle.ts";
function makeContext(providers = new ProviderManager([])): AppContext {
return {
providers,
metrics: new Metrics(),
logBus: new LogBus(),
virtualKeys: new VirtualKeyManager(),
mcp: new MCPRegistry(),
plugins: new PluginManager(),
toolExecutor: new NullToolExecutor(),
version: VERSION,
};
}
const base = "http://gateway.test";
Deno.test("GET /healthz reports ok with version", async () => {
const handler = createHandler(makeContext());
const res = await handler(new Request(`${base}/healthz`));
assertEquals(res.status, 200);
const body = await res.json();
assertEquals(body.status, "ok");
assertEquals(body.version, VERSION);
});
Deno.test("GET /api/version reports gateway and runtime versions", async () => {
const handler = createHandler(makeContext());
const res = await handler(new Request(`${base}/api/version`));
const body = await res.json();
assertEquals(body.version, VERSION);
assertEquals(body.deno, Deno.version.deno);
});
Deno.test("transport plugin hooks wrap routing with transformed request and response", async () => {
const ctx = makeContext();
const observed: string[] = [];
ctx.plugins.register({
name: "transport-test",
onTransportPre: (req) => {
observed.push(`pre:${new URL(req.url).pathname}`);
const headers = new Headers(req.headers);
headers.set("x-plugin-request", "present");
return Promise.resolve(new Request(req, { headers }));
},
onTransportPost: (res) => {
observed.push(`post:${res.status}`);
const headers = new Headers(res.headers);
headers.set("x-plugin-response", "present");
return Promise.resolve(
new Response(res.body, { status: res.status, headers }),
);
},
});
const res = await createHandler(ctx)(new Request(`${base}/healthz`));
assertEquals(observed, ["pre:/healthz", "post:200"]);
assertEquals(res.headers.get("x-plugin-response"), "present");
await res.body?.cancel();
});
Deno.test("POST /v1/chat/completions rejects invalid JSON", async () => {
const handler = createHandler(makeContext());
const res = await handler(
new Request(`${base}/v1/chat/completions`, {
method: "POST",
body: "{not json",
}),
);
assertEquals(res.status, 400);
const body = await res.json();
assertEquals(body.error.type, "invalid_request_error");
});
Deno.test("POST /v1/chat/completions rejects schema-invalid payloads", async () => {
const handler = createHandler(makeContext());
const res = await handler(
new Request(`${base}/v1/chat/completions`, {
method: "POST",
body: JSON.stringify({ garbage: true }),
}),
);
assertEquals(res.status, 400);
const body = await res.json();
assertEquals(body.error.type, "invalid_request_error");
assert(String(body.error.message).includes("model"));
});
Deno.test("POST /v1/chat/completions with no providers returns 503", async () => {
const handler = createHandler(makeContext());
const res = await handler(
new Request(`${base}/v1/chat/completions`, {
method: "POST",
body: JSON.stringify({
model: "gpt-4o",
messages: [{ role: "user", content: "hi" }],
}),
}),
);
assertEquals(res.status, 503);
const body = await res.json();
assertEquals(body.error.type, "provider_error");
});
Deno.test("GET /v1/models lists the aggregated catalog", async () => {
const providers = new ProviderManager([{
id: "openai",
type: "openai",
apiKey: "k",
enabled: true,
models: ["gpt-4o"],
priority: 0,
}]);
const handler = createHandler(makeContext(providers));
const res = await handler(new Request(`${base}/v1/models`));
const body = await res.json();
assertEquals(body.object, "list");
assertEquals(body.data[0].id, "openai/gpt-4o");
});
Deno.test("unknown routes return 404", async () => {
const handler = createHandler(makeContext());
const res = await handler(new Request(`${base}/nope`));
assertEquals(res.status, 404);
await res.body?.cancel();
});