Files
pikasTech-HWLAB/cmd/hwlab-edge-proxy/main.test.ts
T
2026-05-29 03:34:56 +08:00

123 lines
3.9 KiB
TypeScript

import assert from "node:assert/strict";
import { spawn } from "node:child_process";
import { createServer } from "node:http";
import test from "node:test";
const bunCommand = process.env.HWLAB_TEST_BUN_COMMAND || process.env.HWLAB_BUN_COMMAND || (process.versions.bun ? process.execPath : "bun");
test("edge proxy reports local health and proxies live health to upstream", async () => {
const upstream = await startUpstream();
const proxy = await startEdgeProxy(upstream.port);
try {
const health = await fetchJson(`http://127.0.0.1:${proxy.port}/health`);
assert.equal(health.serviceId, "hwlab-edge-proxy");
assert.equal(health.status, "ok");
assert.equal(health.service.role, "public-dev-ingress");
assert.equal(health.details.upstream, `http://127.0.0.1:${upstream.port}`);
assert.equal(health.details.mode, "dev-edge-proxy");
const routes = await fetchJson(`http://127.0.0.1:${proxy.port}/routes`);
assert.equal(routes.serviceId, "hwlab-edge-proxy");
assert.deepEqual(routes.routes, [{
pathPrefix: "/",
upstream: `http://127.0.0.1:${upstream.port}`,
mode: "http-proxy"
}]);
const live = await fetchJson(`http://127.0.0.1:${proxy.port}/health/live`);
assert.equal(live.serviceId, "hwlab-cloud-api");
assert.equal(live.environment, "v02");
assert.equal(upstream.captured.method, "GET");
assert.equal(upstream.captured.url, "/health/live");
} finally {
await proxy.stop();
await upstream.stop();
}
});
async function startUpstream() {
let captured = null;
const server = createServer(async (request, response) => {
const chunks = [];
for await (const chunk of request) chunks.push(chunk);
captured = {
method: request.method,
url: request.url,
body: Buffer.concat(chunks).toString("utf8")
};
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify({
serviceId: "hwlab-cloud-api",
environment: "v02",
status: "live"
}));
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
return {
port: server.address().port,
get captured() {
return captured;
},
stop: () => new Promise((resolve) => server.close(resolve))
};
}
async function startEdgeProxy(upstreamPort) {
const port = await freePort();
const child = spawn(bunCommand, ["run", "cmd/hwlab-edge-proxy/main.ts"], {
cwd: process.cwd(),
env: {
...process.env,
HWLAB_EDGE_HOST: "127.0.0.1",
HWLAB_EDGE_PORT: String(port),
HWLAB_EDGE_UPSTREAM: `http://127.0.0.1:${upstreamPort}`
},
stdio: ["ignore", "pipe", "pipe"]
});
await waitForListening(child, "edge proxy");
return {
port,
stop: () => stopChild(child)
};
}
async function fetchJson(url, options = {}) {
const response = await fetch(url, options);
assert.equal(response.ok, true, `${url} returned ${response.status}`);
return response.json();
}
async function freePort() {
const server = createServer();
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
const port = server.address().port;
await new Promise((resolve) => server.close(resolve));
return port;
}
async function waitForListening(child, label) {
let stderr = "";
child.stderr.on("data", (chunk) => {
stderr += chunk;
});
await new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error(`${label} did not start: ${stderr}`)), 5000);
child.stdout.on("data", (chunk) => {
if (chunk.toString().includes("listening")) {
clearTimeout(timer);
resolve();
}
});
child.on("exit", (code) => {
clearTimeout(timer);
reject(new Error(`${label} exited early code=${code}: ${stderr}`));
});
});
}
async function stopChild(child) {
if (child.exitCode !== null) return;
child.kill("SIGTERM");
await new Promise((resolve) => child.once("exit", resolve));
}