71 lines
2.3 KiB
TypeScript
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()));
|
|
}
|