Refactor runtime around isolated bot instances
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import net from "node:net";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
import { parseConfig } from "../src/config.js";
|
||||
import { createGatewayRuntime, startServer } from "../src/server.js";
|
||||
|
||||
const fixture = path.resolve("test/fixtures/fake-acp-agent.mjs");
|
||||
|
||||
test("server mounts only selected platform and exposes non-secret identity health", { concurrency: false }, async () => {
|
||||
const home = await fs.promises.mkdtemp(path.join(os.tmpdir(), "gori-server-"));
|
||||
const previous = process.env.GORI_AGENT_HOME; process.env.GORI_AGENT_HOME = home;
|
||||
const secret = "never-expose-this-secret";
|
||||
const config = parseConfig({
|
||||
configVersion: 3,
|
||||
bot: { id: "route-bot", workspace: path.resolve("."), persona: "", agent: { id: "fake", command: process.execPath, args: [fixture] }, permissions: { mode: "deny" } },
|
||||
gateway: { platform: { type: "webhook", secret } },
|
||||
runtime: {}
|
||||
});
|
||||
const runtime = await createGatewayRuntime(config);
|
||||
const server = runtime.app.listen(0, "127.0.0.1");
|
||||
await new Promise<void>((resolve) => server.once("listening", resolve));
|
||||
try {
|
||||
const address = server.address(); assert.ok(address && typeof address !== "string");
|
||||
const base = `http://127.0.0.1:${address.port}`;
|
||||
const health = await (await fetch(`${base}/health`)).text();
|
||||
assert.match(health, /"configVersion":3/); assert.match(health, /"botId":"route-bot"/); assert.match(health, /"platform":"webhook"/); assert.doesNotMatch(health, new RegExp(secret));
|
||||
assert.equal((await fetch(`${base}/webhook/qq`, { method: "POST", headers: { "content-type": "application/json" }, body: "{}" })).status, 404);
|
||||
assert.notEqual((await fetch(`${base}/webhook/generic`, { method: "POST", headers: { "content-type": "application/json" }, body: "{}" })).status, 404);
|
||||
} finally {
|
||||
await new Promise<void>((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
|
||||
await runtime.shutdown();
|
||||
if (previous === undefined) delete process.env.GORI_AGENT_HOME; else process.env.GORI_AGENT_HOME = previous;
|
||||
}
|
||||
});
|
||||
|
||||
test("QQ websocket mode does not mount the QQ webhook route", { concurrency: false }, async () => {
|
||||
const home = await fs.promises.mkdtemp(path.join(os.tmpdir(), "gori-server-qq-"));
|
||||
const previous = process.env.GORI_AGENT_HOME; process.env.GORI_AGENT_HOME = home;
|
||||
const config = parseConfig({
|
||||
configVersion: 3,
|
||||
bot: { id: "qq-bot", workspace: path.resolve("."), persona: "", agent: { id: "fake", command: process.execPath, args: [fixture] }, permissions: { mode: "deny" } },
|
||||
gateway: { platform: { type: "qq", connectionMode: "websocket", appId: "id", clientSecret: "secret", botNames: ["Bot"] } },
|
||||
runtime: {}
|
||||
});
|
||||
const runtime = await createGatewayRuntime(config);
|
||||
const server = runtime.app.listen(0, "127.0.0.1");
|
||||
await new Promise<void>((resolve) => server.once("listening", resolve));
|
||||
try {
|
||||
const address = server.address(); assert.ok(address && typeof address !== "string");
|
||||
const response = await fetch(`http://127.0.0.1:${address.port}/webhook/qq`, { method: "POST", headers: { "content-type": "application/json" }, body: "{}" });
|
||||
assert.equal(response.status, 404);
|
||||
} finally {
|
||||
await new Promise<void>((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
|
||||
await runtime.shutdown();
|
||||
if (previous === undefined) delete process.env.GORI_AGENT_HOME; else process.env.GORI_AGENT_HOME = previous;
|
||||
}
|
||||
});
|
||||
|
||||
test("listen failure releases the session state lock", { concurrency: false }, async () => {
|
||||
const home = await fs.promises.mkdtemp(path.join(os.tmpdir(), "gori-server-conflict-"));
|
||||
const previous = process.env.GORI_AGENT_HOME; process.env.GORI_AGENT_HOME = home;
|
||||
const occupied = net.createServer();
|
||||
await new Promise<void>((resolve) => occupied.listen(0, "127.0.0.1", resolve));
|
||||
const address = occupied.address(); assert.ok(address && typeof address !== "string");
|
||||
const config = parseConfig({
|
||||
configVersion: 3,
|
||||
bot: { id: "conflict-bot", workspace: path.resolve("."), persona: "", agent: { id: "fake", command: process.execPath, args: [fixture] }, permissions: { mode: "deny" } },
|
||||
gateway: { server: { host: "127.0.0.1", port: address.port }, platform: { type: "webhook", secret: "secret" } },
|
||||
runtime: {}
|
||||
});
|
||||
try {
|
||||
await assert.rejects(startServer(config), /EADDRINUSE/);
|
||||
const runtime = await createGatewayRuntime(config);
|
||||
await runtime.shutdown();
|
||||
} finally {
|
||||
await new Promise<void>((resolve, reject) => occupied.close((error) => error ? reject(error) : resolve()));
|
||||
if (previous === undefined) delete process.env.GORI_AGENT_HOME; else process.env.GORI_AGENT_HOME = previous;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user