feat: rebuild xiteng.site homelab platform
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
import assert from "node:assert/strict";
|
||||
import {mkdtempSync, rmSync, writeFileSync} from "node:fs";
|
||||
import http from "node:http";
|
||||
import {tmpdir} from "node:os";
|
||||
import path from "node:path";
|
||||
import {spawn} from "node:child_process";
|
||||
|
||||
const root = process.cwd();
|
||||
const temporaryDirectory = mkdtempSync(path.join(tmpdir(), "xiteng-chat-history-test-"));
|
||||
const databasePath = path.join(temporaryDirectory, "chat.db");
|
||||
const tokenPath = path.join(temporaryDirectory, "service-token");
|
||||
writeFileSync(tokenPath, "history-test-token");
|
||||
|
||||
function availablePort() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = http.createServer();
|
||||
server.once("error", reject);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const port = server.address().port;
|
||||
server.close(() => resolve(port));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function waitForServer(url, child) {
|
||||
const deadline = Date.now() + 30000;
|
||||
while (Date.now() < deadline) {
|
||||
if (child.exitCode !== null) throw new Error(`Bun server exited with code ${child.exitCode}`);
|
||||
try {
|
||||
if ((await fetch(url)).ok) return;
|
||||
} catch {}
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
throw new Error("Timed out waiting for history test server");
|
||||
}
|
||||
|
||||
async function startServer() {
|
||||
const port = await availablePort();
|
||||
const child = spawn(process.execPath, [path.join(root, "src/server.ts")], {
|
||||
cwd: root,
|
||||
env: {
|
||||
...process.env,
|
||||
PORT: String(port),
|
||||
STATIC_ROOT: path.join(root, "dist"),
|
||||
CHAT_DATABASE_PATH: databasePath,
|
||||
KEY_VAULT_URL: "http://127.0.0.1:1",
|
||||
KEY_VAULT_TOKEN_FILE: tokenPath
|
||||
},
|
||||
stdio: "ignore"
|
||||
});
|
||||
await waitForServer(`http://127.0.0.1:${port}/api/health`, child);
|
||||
return {child, origin: `http://127.0.0.1:${port}`};
|
||||
}
|
||||
|
||||
function stopServer(child) {
|
||||
if (child.exitCode !== null) return Promise.resolve();
|
||||
return new Promise((resolve) => {
|
||||
child.once("exit", resolve);
|
||||
child.kill("SIGTERM");
|
||||
});
|
||||
}
|
||||
|
||||
async function api(origin, identity, pathname, init = {}) {
|
||||
const response = await fetch(`${origin}${pathname}`, {
|
||||
...init,
|
||||
headers: {
|
||||
"X-Authentik-Username": identity.username,
|
||||
"X-Authentik-Uid": identity.sub,
|
||||
...(init.body ? {"Content-Type": "application/json"} : {}),
|
||||
...(init.headers || {})
|
||||
}
|
||||
});
|
||||
const payload = response.status === 204 ? null : await response.json();
|
||||
return {response, payload};
|
||||
}
|
||||
|
||||
const owner = {username: "history-owner", sub: "owner-sub"};
|
||||
const other = {username: "history-other", sub: "other-sub"};
|
||||
let server;
|
||||
try {
|
||||
server = await startServer();
|
||||
const initialSettings = {reasoning: "low", showReasoningSummary: false, temperature: null, maxOutputTokens: null};
|
||||
const createdResult = await api(server.origin, owner, "/api/conversations", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({providerId: "openai", model: "gpt-test", generationSettings: initialSettings})
|
||||
});
|
||||
assert.equal(createdResult.response.status, 201);
|
||||
assert.deepEqual(createdResult.payload.conversation.generationSettings, initialSettings);
|
||||
const conversationId = createdResult.payload.conversation.id;
|
||||
const messages = [
|
||||
{id: "user-1", role: "user", parts: [{type: "text", text: "persistent question"}]},
|
||||
{id: "assistant-1", role: "assistant", parts: [{type: "reasoning", text: "persistent reasoning"}, {type: "text", text: "persistent answer"}], metadata: {custom: {response: {providerId: "openai", model: "gpt-test", durationMs: 2000, outputTokens: 40, tokensPerSecond: 20}}}}
|
||||
];
|
||||
const savedResult = await api(server.origin, owner, `/api/conversations/${conversationId}`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({providerId: "openai", model: "gpt-test", messages})
|
||||
});
|
||||
assert.equal(savedResult.response.status, 200);
|
||||
assert.equal(savedResult.payload.conversation.title, "persistent question");
|
||||
assert.equal(savedResult.payload.conversation.messageCount, 2);
|
||||
const updatedSettings = {reasoning: "high", showReasoningSummary: true, temperature: 0.7, maxOutputTokens: 4096};
|
||||
const settingsResult = await api(server.origin, owner, `/api/conversations/${conversationId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify({providerId: "openai", model: "gpt-test", generationSettings: updatedSettings})
|
||||
});
|
||||
assert.equal(settingsResult.response.status, 200);
|
||||
|
||||
await stopServer(server.child);
|
||||
server = await startServer();
|
||||
const restored = await api(server.origin, owner, `/api/conversations/${conversationId}`);
|
||||
assert.equal(restored.response.status, 200);
|
||||
assert.deepEqual(restored.payload.conversation.messages, messages);
|
||||
assert.deepEqual(restored.payload.conversation.generationSettings, updatedSettings);
|
||||
|
||||
const ownerList = await api(server.origin, owner, "/api/conversations");
|
||||
assert.equal(ownerList.payload.conversations.length, 1);
|
||||
assert.equal(ownerList.payload.conversations[0].id, conversationId);
|
||||
|
||||
const otherList = await api(server.origin, other, "/api/conversations");
|
||||
assert.deepEqual(otherList.payload.conversations, []);
|
||||
assert.equal((await api(server.origin, other, `/api/conversations/${conversationId}`)).response.status, 404);
|
||||
assert.equal((await api(server.origin, other, `/api/conversations/${conversationId}`, {method: "DELETE"})).response.status, 404);
|
||||
|
||||
assert.equal((await api(server.origin, owner, `/api/conversations/${conversationId}`, {method: "DELETE"})).response.status, 204);
|
||||
assert.equal((await api(server.origin, owner, `/api/conversations/${conversationId}`)).response.status, 404);
|
||||
console.log("Chat history API tests passed");
|
||||
} finally {
|
||||
if (server) await stopServer(server.child);
|
||||
rmSync(temporaryDirectory, {recursive: true, force: true});
|
||||
}
|
||||
Reference in New Issue
Block a user