fix: emit opencode event stream otel on client close

This commit is contained in:
UniDesk Codex
2026-06-30 14:40:15 +08:00
parent a1e9a5200a
commit d42007c04e
3 changed files with 162 additions and 9 deletions
@@ -825,6 +825,88 @@ test("cloud web OpenCode proxy emits bounded OTLP span", async () => {
}
});
test("cloud web OpenCode event stream emits rewrite OTLP stats when the client closes", async () => {
const otelBodies = [];
const otel = createServer(async (request, response) => {
let body = "";
for await (const chunk of request) body += chunk;
otelBodies.push(JSON.parse(body));
response.writeHead(200, { "content-type": "application/json" });
response.end("{}\n");
});
await listen(otel);
const restoreEnv = withEnv({ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: `${serverUrl(otel)}/v1/traces` });
const cloudApi = createServer((request, response) => {
request.resume();
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify({ authenticated: request.headers.cookie === "hwlab_session=session-a" }));
});
const opencodeResponses = [];
const opencode = createServer((request, response) => {
request.resume();
opencodeResponses.push(response);
response.writeHead(200, { "content-type": "text/event-stream; charset=utf-8" });
response.write('data: {"directory":"/workspace","payload":{"type":"session.status","properties":{"sessionID":"ses_1"}}}\n\n');
});
await listen(cloudApi);
await listen(opencode);
const cloudWeb = createCloudWebServer({
serviceId: "hwlab-cloud-web",
roots: [],
cloudApiBaseUrl: serverUrl(cloudApi),
cloudApiProxyTimeoutMs: 1000,
opencodeUpstreamUrl: serverUrl(opencode),
opencodeProxyHost: "127.0.0.1",
opencodeProxyTimeoutMs: 1000,
opencodeUsername: "oc_user",
opencodePassword: "oc_password",
opencodeEventDirectoryRewrite: { from: "/workspace", to: "/" },
healthPayload: () => ({ status: "ok" }),
sendJson(response, statusCode, body) {
const payload = JSON.stringify(body);
response.writeHead(statusCode, { "content-type": "application/json", "content-length": Buffer.byteLength(payload) });
response.end(payload);
}
});
await listen(cloudWeb);
try {
const response = await fetch(`${serverUrl(cloudWeb)}/global/event`, {
headers: { accept: "text/event-stream", cookie: "hwlab_session=session-a" }
});
assert.equal(response.status, 200);
const reader = response.body.getReader();
const first = await reader.read();
assert.equal(first.done, false);
const text = new TextDecoder().decode(first.value);
assert.match(text, /"directory":"\/"/u);
await reader.cancel();
await waitFor(() => otelBodies.length > 0, "expected OpenCode event stream OTel span");
const spans = otelBodies.flatMap((body) => body.resourceSpans?.flatMap((resourceSpan) => resourceSpan.scopeSpans?.flatMap((scopeSpan) => scopeSpan.spans ?? []) ?? []) ?? []);
const span = spans.find((item) => item.name === "opencode.proxy.request");
assert.ok(span, "expected opencode.proxy.request span");
const attrs = new Map((span.attributes ?? []).map((entry) => [entry.key, entry.value?.stringValue ?? entry.value?.intValue ?? entry.value?.boolValue]));
assert.equal(attrs.get("http.route"), "/global/event");
assert.equal(attrs.get("opencode.proxy.streaming"), true);
assert.equal(attrs.get("opencode.proxy.sse.directory_rewrite_enabled"), true);
assert.equal(attrs.get("opencode.proxy.sse.directory_rewrite_from"), "/workspace");
assert.equal(attrs.get("opencode.proxy.sse.directory_rewrite_to"), "/");
assert.equal(attrs.get("opencode.proxy.sse.directory_rewrite_data_lines"), "1");
assert.equal(attrs.get("opencode.proxy.sse.directory_rewrite_events"), "1");
assert.equal(attrs.get("opencode.proxy.sse.directory_rewrite_json_errors"), "0");
} finally {
for (const response of opencodeResponses) response.destroy();
restoreEnv();
await close(cloudWeb);
await close(opencode);
await close(cloudApi);
await close(otel);
}
});
test("cloud web OpenCode proxy accepts short-lived tickets minted by the shell", async () => {
const restoreEnv = withEnv({
HWLAB_CLOUD_WEB_DISPLAY_TIME_ZONE: "Asia/Shanghai",