fix: expose hwpod node ops otel trace diagnostics
This commit is contained in:
@@ -8,8 +8,23 @@ import { createCloudApiBunServer } from "./bun-server.ts";
|
||||
import { createCloudApiServer } from "./server.ts";
|
||||
import { connectHwpodNodeWs, createHwpodNodeServer } from "../../tools/src/hwpod-node-lib.ts";
|
||||
|
||||
function createHwpodTestCloudApiServer(options: any = {}) {
|
||||
return createCloudApiServer({ accessController: allowAllAccessController(), ...options });
|
||||
}
|
||||
|
||||
function allowAllAccessController() {
|
||||
return {
|
||||
required: false,
|
||||
configureCodeAgentWorkspaceContext() {},
|
||||
async requireNavAccess() { return true; },
|
||||
async authenticate() {
|
||||
return { ok: true, status: 200, actor: { id: "usr_hwpod_test", role: "admin" }, session: { id: "uss_hwpod_test" } };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test("cloud-api exposes hwpod-node-ops contract on /v1", async () => {
|
||||
const server = createCloudApiServer();
|
||||
const server = createHwpodTestCloudApiServer();
|
||||
await listen(server);
|
||||
try {
|
||||
const response = await fetch(`${serverUrl(server)}/v1`);
|
||||
@@ -31,7 +46,7 @@ test("cloud-api exposes hwpod-node-ops contract on /v1", async () => {
|
||||
});
|
||||
|
||||
test("cloud-api exposes hwlab-node Python update metadata", async () => {
|
||||
const server = createCloudApiServer({
|
||||
const server = createHwpodTestCloudApiServer({
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
HWLAB_PUBLIC_ENDPOINT: "https://hwlab.pikapython.com",
|
||||
@@ -63,7 +78,7 @@ test("cloud-api exposes hwlab-node Python update metadata", async () => {
|
||||
});
|
||||
|
||||
test("cloud-api serves bundled hwlab-node Python updater artifact by default", async () => {
|
||||
const server = createCloudApiServer({ env: { PATH: process.env.PATH, HWLAB_PUBLIC_ENDPOINT: "https://hwlab.pikapython.com" } });
|
||||
const server = createHwpodTestCloudApiServer({ env: { PATH: process.env.PATH, HWLAB_PUBLIC_ENDPOINT: "https://hwlab.pikapython.com" } });
|
||||
await listen(server);
|
||||
try {
|
||||
const response = await fetch(`${serverUrl(server)}/v1/hwlab-node/update?current=0.1.0&channel=stable&platform=windows`);
|
||||
@@ -90,7 +105,7 @@ test("cloud-api discovers preinstalled workspace hwpod-specs without hardcoded d
|
||||
await mkdir(specDir, { recursive: true });
|
||||
await writeFile(path.join(specDir, "hwpod-spec.yaml"), sampleSpecYaml(), "utf8");
|
||||
await writeFile(path.join(specDir, "hwpod-spec.meta.json"), JSON.stringify({ source: { kind: "preinstalled-verified-spec", caseRepo: "pikasTech/hwlab-case-registry", caseId: "d601-f103-v2-compile" } }), "utf8");
|
||||
const server = createCloudApiServer({ env: { PATH: process.env.PATH, HWLAB_CODE_AGENT_WORKSPACE: root } });
|
||||
const server = createHwpodTestCloudApiServer({ env: { PATH: process.env.PATH, HWLAB_CODE_AGENT_WORKSPACE: root } });
|
||||
await listen(server);
|
||||
try {
|
||||
const response = await fetch(`${serverUrl(server)}/v1/hwpod/specs`);
|
||||
@@ -118,7 +133,7 @@ test("cloud-api discovers configmap-mounted registry hwpod-spec symlinks", async
|
||||
const targetPath = path.join(dataDir, "constart-71freq-c.yaml");
|
||||
await writeFile(targetPath, sampleConstartSpecYaml(), "utf8");
|
||||
await symlink(targetPath, path.join(registryDir, "constart-71freq-c.yaml"));
|
||||
const server = createCloudApiServer({
|
||||
const server = createHwpodTestCloudApiServer({
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
HWLAB_CODE_AGENT_WORKSPACE: root,
|
||||
@@ -148,7 +163,7 @@ test("cloud-api probes discovered hwpod-spec availability through node-ops", asy
|
||||
await mkdir(specDir, { recursive: true });
|
||||
await writeFile(path.join(specDir, "hwpod-spec.yaml"), sampleSpecYaml(), "utf8");
|
||||
const seen: any[] = [];
|
||||
const server = createCloudApiServer({
|
||||
const server = createHwpodTestCloudApiServer({
|
||||
env: { PATH: process.env.PATH, HWLAB_CODE_AGENT_WORKSPACE: root },
|
||||
hwpodNodeOpsHandler: async (plan: any) => {
|
||||
seen.push(plan);
|
||||
@@ -174,7 +189,7 @@ test("cloud-api probes discovered hwpod-spec availability through node-ops", asy
|
||||
|
||||
test("cloud-api forwards valid hwpod-node-ops plans to injected node handler", async () => {
|
||||
const seen: any[] = [];
|
||||
const server = createCloudApiServer({
|
||||
const server = createHwpodTestCloudApiServer({
|
||||
hwpodNodeOpsHandler: async (plan: any, context: any) => {
|
||||
seen.push({ plan, context });
|
||||
return {
|
||||
@@ -206,20 +221,27 @@ test("cloud-api forwards valid hwpod-node-ops plans to injected node handler", a
|
||||
});
|
||||
|
||||
test("cloud-api returns blocked payload when hwpod-node is not wired yet", async () => {
|
||||
const server = createCloudApiServer();
|
||||
const server = createHwpodTestCloudApiServer();
|
||||
const otelTraceId = "0123456789abcdef0123456789abcdef";
|
||||
await listen(server);
|
||||
try {
|
||||
const response = await fetch(`${serverUrl(server)}/v1/hwpod-node-ops`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
headers: { "content-type": "application/json", "x-hwlab-otel-trace-id": otelTraceId },
|
||||
body: JSON.stringify(samplePlan())
|
||||
});
|
||||
const payload = await response.json();
|
||||
assert.equal(response.status, 200);
|
||||
assert.equal(response.headers.get("x-hwlab-otel-trace-id"), otelTraceId);
|
||||
assert.equal(payload.ok, false);
|
||||
assert.equal(payload.status, "blocked");
|
||||
assert.equal(payload.otelTraceId, otelTraceId);
|
||||
assert.equal(payload.requestMeta.otelTraceId, otelTraceId);
|
||||
assert.equal(payload.blocker.code, "hwpod_node_unavailable");
|
||||
assert.equal(payload.blocker.otelTraceId, otelTraceId);
|
||||
assert.equal(payload.blocker.diagnostic.traceLine, `OTel traceId: ${otelTraceId}`);
|
||||
assert.equal(payload.results[0].blocker.layer, "hwpod-node");
|
||||
assert.match(payload.results[0].blocker.userMessage, /OTel traceId:/u);
|
||||
} finally {
|
||||
await close(server);
|
||||
}
|
||||
@@ -228,7 +250,7 @@ test("cloud-api returns blocked payload when hwpod-node is not wired yet", async
|
||||
test("cloud-api forwards hwpod-node-ops to configured thin hwpod-node URL", async () => {
|
||||
const node = createHwpodNodeServer({ nodeId: "pc-host-1" });
|
||||
await listen(node);
|
||||
const server = createCloudApiServer({
|
||||
const server = createHwpodTestCloudApiServer({
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
HWLAB_HWPOD_NODE_OPS_URL: `${serverUrl(node)}/v1/hwpod-node-ops`
|
||||
@@ -258,7 +280,7 @@ test("cloud-api forwards hwpod-node-ops to configured thin hwpod-node URL", asyn
|
||||
test("cloud-api blocks direct hwpod-node URL when target node id does not match", async () => {
|
||||
const node = createHwpodNodeServer({ nodeId: "g14-host-hwpod-node" });
|
||||
await listen(node);
|
||||
const server = createCloudApiServer({
|
||||
const server = createHwpodTestCloudApiServer({
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
HWPOD_NODE_ID: "g14-host-hwpod-node",
|
||||
@@ -290,7 +312,7 @@ test("cloud-api blocks direct hwpod-node URL when target node id does not match"
|
||||
});
|
||||
|
||||
test("cloud-api blocks direct hwpod-node URL when node identity is not visible", async () => {
|
||||
const target = createCloudApiServer({
|
||||
const target = createHwpodTestCloudApiServer({
|
||||
hwpodNodeOpsHandler: async (plan: any) => ({
|
||||
ok: true,
|
||||
status: "completed",
|
||||
@@ -298,7 +320,7 @@ test("cloud-api blocks direct hwpod-node URL when node identity is not visible",
|
||||
})
|
||||
});
|
||||
await listen(target);
|
||||
const server = createCloudApiServer({
|
||||
const server = createHwpodTestCloudApiServer({
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
HWLAB_HWPOD_NODE_OPS_URL: `${serverUrl(target)}/v1/hwpod-node-ops`
|
||||
@@ -325,7 +347,7 @@ test("cloud-api blocks direct hwpod-node URL when node identity is not visible",
|
||||
|
||||
test("cloud-api dispatches hwpod-node-ops to outbound WebSocket hwpod-node by nodeId", async () => {
|
||||
const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-hwpod-node-ws-"));
|
||||
const runtime = await createCloudApiBunServer({ host: "127.0.0.1", port: 0, env: { PATH: process.env.PATH } });
|
||||
const runtime = await createCloudApiBunServer({ host: "127.0.0.1", port: 0, env: { PATH: process.env.PATH }, accessController: allowAllAccessController() });
|
||||
const connector = connectHwpodNodeWs({ cloudUrl: runtime.url, nodeId: "pc-host-1", reconnect: false, heartbeatIntervalMs: 1000 });
|
||||
try {
|
||||
await writeFile(path.join(root, "main.c"), "int main(void) { return 0; }\n", "utf8");
|
||||
@@ -352,7 +374,7 @@ test("cloud-api dispatches hwpod-node-ops to outbound WebSocket hwpod-node by no
|
||||
});
|
||||
|
||||
test("cloud-api rejects unsupported hwpod-node ops before forwarding", async () => {
|
||||
const server = createCloudApiServer({
|
||||
const server = createHwpodTestCloudApiServer({
|
||||
hwpodNodeOpsHandler: async () => {
|
||||
throw new Error("must not be called");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user