Files
homelab/ai-gateway/server.test.mjs
T

111 lines
4.2 KiB
JavaScript

import assert from "node:assert/strict";
import {spawn} from "node:child_process";
import {randomBytes} from "node:crypto";
import {mkdtempSync, rmSync, writeFileSync} from "node:fs";
import http from "node:http";
import {tmpdir} from "node:os";
import {join} from "node:path";
const directory = mkdtempSync(join(tmpdir(), "xiteng-key-vault-api-test-"));
writeFileSync(join(directory, "master-key"), randomBytes(32).toString("base64"));
writeFileSync(join(directory, "service-token"), "integration-service-token");
const portProbe = http.createServer();
await new Promise((resolve) => portProbe.listen(0, "127.0.0.1", resolve));
const port = portProbe.address().port;
await new Promise((resolve) => portProbe.close(resolve));
const service = spawn(process.execPath, ["server.mjs"], {
cwd: new URL(".", import.meta.url),
env: {
...process.env,
PORT: String(port),
DATABASE_PATH: join(directory, "vault.db"),
MASTER_KEY_FILE: join(directory, "master-key"),
SERVICE_TOKEN_FILE: join(directory, "service-token"),
PROVIDER_CATALOG_FILE: new URL("providers.json", import.meta.url).pathname
},
stdio: ["ignore", "pipe", "pipe"]
});
let logs = "";
service.stdout.on("data", (chunk) => { logs += chunk; });
service.stderr.on("data", (chunk) => { logs += chunk; });
function request(pathname, {method = "GET", body} = {}) {
return fetch(`http://127.0.0.1:${port}${pathname}`, {
method,
headers: {
"Authorization": "Bearer integration-service-token",
"Accept": "application/json",
...(body ? {"Content-Type": "application/json"} : {}),
"X-Key-Vault-Actor-Issuer": "https://auth.xiteng.site",
"X-Key-Vault-Actor-Sub": "integration-user",
"X-Key-Vault-Actor-Username": "integration"
},
body: body ? JSON.stringify(body) : undefined
});
}
try {
let ready = false;
for (let attempt = 0; attempt < 50; attempt += 1) {
try {
if ((await fetch(`http://127.0.0.1:${port}/healthz`)).ok) {
ready = true;
break;
}
} catch {}
await new Promise((resolve) => setTimeout(resolve, 50));
}
assert.equal(ready, true, logs || "Key Vault did not start");
const providersResponse = await request("/v1/providers");
assert.equal(providersResponse.status, 200);
const providers = await providersResponse.json();
assert.ok(providers.providers.some((provider) => provider.id === "openai"));
assert.ok(providers.providers.some((provider) => provider.id === "ollama" && provider.credentialState === "local"));
const customResponse = await request("/v1/providers", {
method: "POST",
body: {
id: "integration-provider",
name: "Integration Provider",
api: "openai-completions",
connection: {type: "backend", baseUrl: "https://example.com/v1", proxy: null},
auth: {type: "bearer"},
defaultModel: "test-model",
discovery: {type: "openai-models-list", url: "https://example.com/v1/models"}
}
});
assert.equal(customResponse.status, 200);
const savedCustom = await customResponse.json();
assert.equal(savedCustom.provider.discovery.url, "https://example.com/v1/models");
assert.equal("models" in savedCustom.provider, false);
const createdResponse = await request("/v1/credentials", {
method: "POST",
body: {providerId: "integration-provider", name: "default", secret: {provider: {apiKey: "provider-secret"}}}
});
assert.equal(createdResponse.status, 201);
const resolvedResponse = await request("/v1/resolve", {
method: "POST",
body: {providerId: "integration-provider", credentialName: "default"}
});
assert.equal(resolvedResponse.status, 200);
const resolved = await resolvedResponse.json();
assert.equal(resolved.provider.connection.baseUrl, "https://example.com/v1");
assert.equal(resolved.credential.secret.provider.apiKey, "provider-secret");
const frontendCredential = await request("/v1/credentials", {
method: "POST",
body: {providerId: "ollama", name: "default", secret: "browser-only"}
});
assert.equal(frontendCredential.status, 409);
console.log("Key Vault API tests passed");
} finally {
service.kill("SIGTERM");
await new Promise((resolve) => service.once("exit", resolve));
rmSync(directory, {recursive: true, force: true});
}