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 path from "node:path";
|
||||
import test from "node:test";
|
||||
import {
|
||||
collectUsedInstancePorts,
|
||||
parseServerHost,
|
||||
parseServerPort,
|
||||
suggestAvailablePort
|
||||
} from "../src/cli/setup-server.js";
|
||||
|
||||
test("server host parser accepts bind addresses and hostnames", () => {
|
||||
for (const host of ["0.0.0.0", "127.0.0.1", "::", "2001:db8::1", "localhost", "gateway.example.com"]) {
|
||||
assert.equal(parseServerHost(host), host);
|
||||
}
|
||||
});
|
||||
|
||||
test("server host parser rejects URLs, ports, paths, whitespace, and invalid labels", () => {
|
||||
for (const host of ["", "http://localhost", "localhost:8787", "[::1]", "host/path", "bad host", "-bad.example", "bad-.example"]) {
|
||||
assert.throws(() => parseServerHost(host), /server host/);
|
||||
}
|
||||
});
|
||||
|
||||
test("server port parser accepts only decimal ports in range", () => {
|
||||
assert.equal(parseServerPort("1"), 1);
|
||||
assert.equal(parseServerPort("8787"), 8787);
|
||||
assert.equal(parseServerPort("65535"), 65_535);
|
||||
for (const port of ["", "0", "65536", "1.5", "0x20", "8e3", "-1"]) {
|
||||
assert.throws(() => parseServerPort(port), /server port/);
|
||||
}
|
||||
});
|
||||
|
||||
test("available port suggestion advances without wrapping", () => {
|
||||
assert.equal(suggestAvailablePort(8787, new Set([8787, 8788])), 8789);
|
||||
assert.throws(() => suggestAvailablePort(65_535, new Set([65_535])), /No unassigned instance port/);
|
||||
});
|
||||
|
||||
test("instance port scan reads only valid Config v3 regular files and excludes target", (t) => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "gori-setup-ports-"));
|
||||
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
||||
|
||||
const writePeer = (name: string, value: unknown): string => {
|
||||
const directory = path.join(root, name);
|
||||
fs.mkdirSync(directory);
|
||||
const file = path.join(directory, "config.json");
|
||||
fs.writeFileSync(file, JSON.stringify(value));
|
||||
return file;
|
||||
};
|
||||
const peer = (port: number, configVersion: number = 3) => ({
|
||||
configVersion,
|
||||
bot: {
|
||||
id: "peer-bot",
|
||||
workspace: os.tmpdir(),
|
||||
persona: "peer",
|
||||
agent: { id: "test", command: process.execPath, args: [], env: {} },
|
||||
skills: [],
|
||||
permissions: { mode: "deny", allowedTools: [], allowedCommandPatterns: [] }
|
||||
},
|
||||
gateway: {
|
||||
server: { host: "127.0.0.1", port, publicBaseUrl: "" },
|
||||
policy: { allowedUsers: [], allowedChats: [], requireMentionInGroup: true },
|
||||
platform: { type: "webhook", secret: "test-secret" }
|
||||
},
|
||||
runtime: {}
|
||||
});
|
||||
|
||||
writePeer("valid", peer(8787));
|
||||
const excluded = writePeer("current", peer(8788));
|
||||
writePeer("legacy", peer(8789, 2));
|
||||
writePeer("out-of-range", peer(70_000));
|
||||
writePeer("broken", "not an object");
|
||||
fs.writeFileSync(path.join(root, "broken", "config.json"), "{broken");
|
||||
|
||||
const linkedDirectory = path.join(root, "linked");
|
||||
fs.symlinkSync(path.join(root, "valid"), linkedDirectory, "dir");
|
||||
const symlinkConfigDirectory = path.join(root, "symlink-config");
|
||||
fs.mkdirSync(symlinkConfigDirectory);
|
||||
fs.symlinkSync(path.join(root, "valid", "config.json"), path.join(symlinkConfigDirectory, "config.json"));
|
||||
|
||||
assert.deepEqual([...collectUsedInstancePorts(root, excluded)], [8787]);
|
||||
});
|
||||
Reference in New Issue
Block a user