cc-libs/tools/mcp-bridge/test-integration/opencode-proxy.test.ts

71 lines
2.3 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { createServer, type Server } from "node:http";
import type { WebSocketServer } from "ws";
import { formatFailure, startCraftos } from "./harness.js";
import { startOpencodeProxy } from "../src/opencode-proxy.js";
test("libhttpws drives a synchronous opencode call through the bridge proxy", async () => {
const opencode = createServer((_req, res) => {
res.writeHead(200, { "content-type": "application/json" });
res.end(JSON.stringify({ info: { finish: "stop" }, parts: [{ type: "text", text: "pong" }] }));
});
await new Promise<void>((resolve) => opencode.listen(0, "127.0.0.1", resolve));
const opencodeUrl = `http://127.0.0.1:${serverPort(opencode)}`;
const proxy = startOpencodeProxy({ host: "127.0.0.1", port: 0, opencodeUrl });
await waitForListening(proxy);
const proxyUrl = `ws://127.0.0.1:${wssPort(proxy)}`;
const craftos = startCraftos("opencode-proxy-check.lua", {
mountRepo: true,
shellArgs: [proxyUrl],
timeoutMs: 20_000,
});
try {
const result = await craftos.done;
assert.match(result.output, /STATUS=200/, formatFailure("expected STATUS=200", result.output));
assert.match(result.output, /pong/, formatFailure("expected reply body to contain pong", result.output));
} finally {
craftos.abort();
await craftos.done.catch(() => undefined);
await closeWss(proxy);
await new Promise<void>((resolve) => opencode.close(() => resolve()));
}
});
function serverPort(server: Server): number {
const address = server.address();
if (!address || typeof address === "string") {
throw new Error("server has no TCP address");
}
return address.port;
}
function wssPort(proxy: WebSocketServer): number {
const address = proxy.address();
if (!address || typeof address === "string") {
throw new Error("proxy has no TCP address");
}
return address.port;
}
function waitForListening(proxy: WebSocketServer): Promise<void> {
return new Promise((resolve, reject) => {
if (proxy.address()) {
resolve();
return;
}
proxy.once("listening", () => resolve());
proxy.once("error", reject);
});
}
function closeWss(proxy: WebSocketServer): Promise<void> {
for (const client of proxy.clients) {
client.terminate();
}
return new Promise<void>((resolve) => proxy.close(() => resolve()));
}