Files
pikasTech-HWLAB/internal/dev-entrypoint/http.test.mjs
T

164 lines
5.0 KiB
JavaScript

import assert from "node:assert/strict";
import { createServer } from "node:http";
import test from "node:test";
import { cloudWebProxyRoutePolicy } from "./cloud-web-routes.mjs";
import { proxyHttpRequest } from "./http.mjs";
test("cloud web route policy proxies public Code Agent chat without gating other writes", () => {
assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/v1/agent/chat"), {
proxy: true,
authRequired: false,
publicRoute: true,
routeKey: "POST /v1/agent/chat"
});
assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/v1/agent/chat/cancel"), {
proxy: true,
authRequired: false,
publicRoute: true,
routeKey: "POST /v1/agent/chat/cancel"
});
assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/v1/m3/io"), {
proxy: true,
authRequired: true,
publicRoute: false,
routeKey: "POST /v1/m3/io"
});
assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/json-rpc"), {
proxy: true,
authRequired: true,
publicRoute: false,
routeKey: "POST /json-rpc"
});
assert.deepEqual(cloudWebProxyRoutePolicy("GET", "/v1/agent/chat/trace/trc_live"), {
proxy: true,
authRequired: false,
publicRoute: true,
routeKey: "GET /v1/agent/chat/trace/trc_live"
});
assert.deepEqual(cloudWebProxyRoutePolicy("GET", "/v1/agent/chat/result/trc_live"), {
proxy: true,
authRequired: false,
publicRoute: true,
routeKey: "GET /v1/agent/chat/result/trc_live"
});
assert.deepEqual(cloudWebProxyRoutePolicy("GET", "/app.mjs"), {
proxy: false,
authRequired: false,
publicRoute: false,
routeKey: "GET /app.mjs"
});
});
test("dev entrypoint proxy allows slow first response beyond legacy 4500ms", async () => {
const upstream = createServer((request, response) => {
request.resume();
setTimeout(() => {
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify({
status: "completed",
traceId: request.headers["x-trace-id"] ?? null
}));
}, 4700);
});
await listen(upstream);
const proxy = createServer((request, response) => {
proxyHttpRequest({
request,
response,
upstream: serverUrl(upstream),
timeoutMs: 6000
});
});
await listen(proxy);
try {
const startedAt = Date.now();
const response = await fetch(`${serverUrl(proxy)}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_dev-entrypoint-proxy-slow-success"
},
body: JSON.stringify({ message: "列出你能使用的所有skill" })
});
assert.equal(response.status, 200);
assert.equal(Date.now() - startedAt >= 4500, true);
const payload = await response.json();
assert.equal(payload.status, "completed");
assert.equal(payload.traceId, "trc_dev-entrypoint-proxy-slow-success");
} finally {
await close(proxy);
await close(upstream);
}
});
test("dev entrypoint proxy returns 502 when hard timeout expires", async () => {
const upstream = createServer((request, response) => {
request.resume();
setTimeout(() => {
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify({ status: "completed" }));
}, 250);
});
await listen(upstream);
const proxy = createServer((request, response) => {
proxyHttpRequest({
request,
response,
upstream: serverUrl(upstream),
timeoutMs: 50
});
});
await listen(proxy);
try {
const response = await fetch(`${serverUrl(proxy)}/v1/agent/chat`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-trace-id": "trc_dev-entrypoint-proxy-timeout"
},
body: JSON.stringify({ message: "slow" })
});
assert.equal(response.status, 502);
const payload = await response.json();
assert.equal(payload.status, "failed");
assert.equal(payload.error.code, "proxy_timeout");
assert.equal(payload.error.layer, "proxy");
assert.equal(payload.error.category, "timeout");
assert.equal(payload.error.retryable, true);
assert.equal(payload.error.timeoutMs, 50);
assert.equal(payload.error.traceId, "trc_dev-entrypoint-proxy-timeout");
assert.match(payload.error.userMessage, /超过 50ms/u);
assert.match(payload.error.message, /输入已保留/u);
assert.equal(payload.error.blocker.code, "proxy_timeout");
assert.equal(payload.error.blocker.retryable, true);
assert.equal(payload.traceId, "trc_dev-entrypoint-proxy-timeout");
assert.match(payload.message, /Code Agent 代理等待上游超过 50ms/u);
} finally {
await close(proxy);
await close(upstream);
}
});
function listen(server) {
return new Promise((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", resolve);
});
}
function close(server) {
return new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
function serverUrl(server) {
const address = server.address();
return `http://127.0.0.1:${address.port}`;
}