Files
pikasTech-HWLAB/internal/cloud/server-live-builds.test.ts
T
2026-06-05 01:35:35 +08:00

365 lines
13 KiB
TypeScript

import assert from "node:assert/strict";
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { test } from "bun:test";
import { createCloudApiServer } from "./server.ts";
test("cloud api aggregates live HWLAB build times from health and controlled deploy/catalog metadata", async () => {
const healthByPath = new Map([
["/hwlab-cloud-web/health/live", {
serviceId: "hwlab-cloud-web",
status: "ok",
revision: "webabcdef123456",
commit: { id: "webabcdef123456", source: "test" },
image: {
reference: "127.0.0.1:5000/hwlab/hwlab-cloud-web:webabcd",
tag: "webabcd",
digest: "sha256:" + "1".repeat(64)
},
build: {
createdAt: "2026-05-23T02:10:00.000Z",
metadataSource: "runtime-env:HWLAB_BUILD_CREATED_AT"
}
}],
["/hwlab-device-pod/health/live", {
serviceId: "hwlab-device-pod",
status: "ok",
revision: "48dfbf9",
commit: { id: "48dfbf9", source: "test" },
image: {
reference: "127.0.0.1:5000/hwlab/hwlab-device-pod:48dfbf9",
tag: "48dfbf9",
digest: "sha256:" + "2".repeat(64)
}
}],
["/hwlab-agent-skills/health/live", {
serviceId: "hwlab-agent-skills",
status: "ok",
revision: "skillsabcdef123456",
commit: { id: "skillsabcdef123456", source: "test" },
image: {
reference: "127.0.0.1:5000/hwlab/hwlab-agent-skills:skillsabcd",
tag: "skillsabcd",
digest: "sha256:" + "5".repeat(64)
}
}],
["/external/health", {
serviceId: "postgres",
status: "ok",
image: {
reference: "postgres:16",
tag: "16"
}
}]
]);
const liveBuildMetadata = {
deployManifest: {
services: [
{
serviceId: "hwlab-cloud-web",
image: "127.0.0.1:5000/hwlab/hwlab-cloud-web:webcat",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1
},
{
serviceId: "hwlab-device-pod",
image: "127.0.0.1:5000/hwlab/hwlab-device-pod:3df89fe",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1
},
{
serviceId: "hwlab-agent-skills",
image: "127.0.0.1:5000/hwlab/hwlab-agent-skills:skillsabcd",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1,
env: {
HWLAB_COMMIT_ID: "skillsabcdef123456",
HWLAB_IMAGE: "127.0.0.1:5000/hwlab/hwlab-agent-skills:skillsabcd",
HWLAB_IMAGE_TAG: "skillsabcd",
HWLAB_BUILD_CREATED_AT: "2026-05-23T05:30:00.000Z",
HWLAB_BUILD_SOURCE: "deploy-env-test"
}
},
{
serviceId: "hwlab-edge-proxy",
image: "127.0.0.1:5000/hwlab/hwlab-edge-proxy:edgecat",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health",
replicas: 1
},
{
serviceId: "hwlab-extra-lab",
image: "127.0.0.1:5000/hwlab/hwlab-extra-lab:extracat",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1
}
]
},
artifactCatalog: {
services: [
{
serviceId: "hwlab-device-pod",
commitId: "3df89fe",
image: "127.0.0.1:5000/hwlab/hwlab-device-pod:3df89fe",
imageTag: "3df89fe",
digest: "sha256:" + "3".repeat(64),
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
buildCreatedAt: "2026-05-23T04:20:00.000Z",
buildSource: "artifact-catalog-test"
},
{
serviceId: "hwlab-agent-skills",
commitId: "skillsabcdef123456",
image: "127.0.0.1:5000/hwlab/hwlab-agent-skills:skillsabcd",
imageTag: "skillsabcd",
digest: "sha256:" + "5".repeat(64),
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
buildCreatedAt: null,
buildSource: null
},
{
serviceId: "hwlab-extra-lab",
commitId: "extracatabcdef123456",
image: "127.0.0.1:5000/hwlab/hwlab-extra-lab:extracat",
imageTag: "extracat",
digest: "sha256:" + "4".repeat(64),
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
buildCreatedAt: "2026-05-23T03:00:00.000Z",
buildSource: "artifact-catalog-test"
}
]
}
};
const server = createCloudApiServer({
env: {
PATH: "",
HWLAB_COMMIT_ID: "apiabcdef123456",
HWLAB_IMAGE: "127.0.0.1:5000/hwlab/hwlab-cloud-api:apiabcd",
HWLAB_IMAGE_TAG: "apiabcd",
HWLAB_BUILD_CREATED_AT: "2026-05-23T01:00:00.000Z",
HOSTNAME: "hwlab-cloud-api-test-pod",
POD_NAMESPACE: "hwlab-dev",
HWLAB_RUNTIME_CONTAINER: "hwlab-cloud-api",
HWLAB_CLOUD_WEB_SERVICE_URL: "http://live.test/hwlab-cloud-web",
HWLAB_DEVICE_POD_URL: "http://live.test/hwlab-device-pod",
HWLAB_GATEWAY_URL: "http://live.test/missing-gateway",
HWLAB_GATEWAY_SIMU_URL: "http://live.test/missing-gateway-simu",
HWLAB_BOX_SIMU_URL: "http://live.test/missing-box-simu",
HWLAB_PATCH_PANEL_URL: "http://live.test/missing-patch-panel",
HWLAB_ROUTER_URL: "http://live.test/missing-router",
HWLAB_TUNNEL_CLIENT_URL: "http://live.test/missing-tunnel-client",
HWLAB_EDGE_PROXY_URL: "http://live.test/external",
HWLAB_CLI_URL: "http://live.test/missing-cli",
HWLAB_AGENT_SKILLS_URL: "http://live.test/hwlab-agent-skills",
HWLAB_EXTRA_LAB_URL: "http://live.test/missing-extra-lab"
},
liveBuildMetadata,
fetchImpl: async (url) => {
const path = new URL(url).pathname;
const payload = healthByPath.get(path);
if (!payload) {
return {
ok: false,
status: 503,
async text() {
return JSON.stringify({ error: "offline" });
}
};
}
return {
ok: true,
status: 200,
async text() {
return JSON.stringify(payload);
}
};
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/live-builds`);
assert.equal(response.status, 200);
const payload = await response.json();
assert.equal(payload.contractVersion, "live-builds-v1");
assert.equal(payload.latest.serviceId, "hwlab-agent-skills");
assert.equal(payload.latest.build.createdAt, "2026-05-23T05:30:00.000Z");
assert.equal(payload.latest.image.tag, "skillsabcd");
assert.equal(payload.latest.commit.id, "skillsabcdef123456");
assert.equal(payload.latest.build.metadataSource, "deploy-env:HWLAB_BUILD_CREATED_AT");
assert.equal(payload.latest.build.liveMetadataMatch.metadata.imageTag, "skillsabcd");
assert.match(payload.latest.build.liveHealthMissingReason, /匹配的 deploy metadata/u);
const api = payload.services.find((service) => service.serviceId === "hwlab-cloud-api");
assert.equal(api.runtime.pod.name, "hwlab-cloud-api-test-pod");
assert.equal(api.runtime.unideskRoute, "G14:k3s:hwlab-dev:pod:hwlab-cloud-api-test-pod:hwlab-cloud-api");
assert.equal(payload.counts.total, payload.services.length);
assert.equal(payload.counts.external, 2);
assert.equal(payload.counts.withBuildTime, 3);
const devicePod = payload.services.find((service) => service.serviceId === "hwlab-device-pod");
assert.equal(devicePod.build.createdAt, null);
assert.equal(devicePod.image.tag, "48dfbf9");
assert.equal(devicePod.revision, "48dfbf9");
assert.equal(devicePod.build.metadataSource, "live-health:controlled-metadata-mismatch");
assert.equal(devicePod.build.unavailableReason, "构建时间不可用:live tag 与 catalog metadata 不匹配");
assert.match(devicePod.build.unavailableDetail, /live tag 48dfbf9/u);
assert.match(devicePod.build.unavailableDetail, /metadata tag 3df89fe/u);
const extra = payload.services.find((service) => service.serviceId === "hwlab-extra-lab");
assert.equal(extra.build.createdAt, null);
assert.match(extra.build.unavailableReason, /当前 live health 不可用/u);
assert.ok(payload.services.some((service) => service.kind === "external" && service.serviceId === "hwlab-edge-proxy" && service.healthUrl.endsWith("/health")));
assert.ok(payload.services.some((service) => service.kind === "external" && service.serviceId === "hwlab-frpc" && service.image.tag === "v0.68.1"));
assert.ok(payload.services.some((service) => service.serviceId === "hwlab-device-pod"));
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
});
test("cloud api ignores old repository reports and keeps missing buildCreatedAt unavailable", async () => {
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "hwlab-live-builds-"));
const deployDir = path.join(tempRoot, "deploy");
const oldReportDir = path.join(tempRoot, "reports", "dev-gate");
await mkdir(deployDir, { recursive: true });
await mkdir(oldReportDir, { recursive: true });
await writeFile(path.join(deployDir, "deploy.json"), `${JSON.stringify({
services: [
{
serviceId: "hwlab-device-pod",
image: "127.0.0.1:5000/hwlab/hwlab-device-pod:48dfbf9",
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
replicas: 1
}
]
}, null, 2)}\n`);
await writeFile(path.join(deployDir, "artifact-catalog.dev.json"), `${JSON.stringify({
services: [
{
serviceId: "hwlab-device-pod",
commitId: "48dfbf9abcdef",
image: "127.0.0.1:5000/hwlab/hwlab-device-pod:48dfbf9",
imageTag: "48dfbf9",
digest: "sha256:" + "6".repeat(64),
namespace: "hwlab-dev",
profile: "dev",
healthPath: "/health/live",
buildCreatedAt: null,
buildSource: null
}
]
}, null, 2)}\n`);
await writeFile(path.join(oldReportDir, "dev-artifacts.json"), `${JSON.stringify({
artifactPublish: {
services: [
{
serviceId: "hwlab-device-pod",
sourceCommitId: "48dfbf9abcdef",
image: "127.0.0.1:5000/hwlab/hwlab-device-pod:48dfbf9",
imageTag: "48dfbf9",
digest: "sha256:" + "6".repeat(64),
buildCreatedAt: "2099-01-01T00:00:00.000Z",
buildSource: "old-report-must-not-be-read"
}
]
}
}, null, 2)}\n`);
const observe = async () => {
const server = createCloudApiServer({
env: {
PATH: "",
HWLAB_DEVICE_POD_URL: "http://live.test/hwlab-device-pod"
},
repoRoot: tempRoot,
fetchImpl: async (url) => {
if (new URL(url).pathname === "/hwlab-device-pod/health/live") {
return {
ok: true,
status: 200,
async text() {
return JSON.stringify({
serviceId: "hwlab-device-pod",
status: "ok",
revision: "48dfbf9abcdef",
commit: { id: "48dfbf9abcdef", source: "test" },
image: {
reference: "127.0.0.1:5000/hwlab/hwlab-device-pod:48dfbf9",
tag: "48dfbf9",
digest: "sha256:" + "6".repeat(64)
}
});
}
};
}
return {
ok: false,
status: 503,
async text() {
return JSON.stringify({ error: "offline" });
}
};
}
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
try {
const { port } = server.address();
const response = await fetch(`http://127.0.0.1:${port}/v1/live-builds`);
assert.equal(response.status, 200);
return response.json();
} finally {
await new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}
};
try {
const withOldReport = await observe();
await rm(path.join(tempRoot, "reports"), { recursive: true, force: true });
const withoutOldReport = await observe();
const summarize = (payload) => {
const manager = payload.services.find((service) => service.serviceId === "hwlab-device-pod");
return {
latest: payload.latest,
source: payload.source,
createdAt: manager.build.createdAt,
metadataSource: manager.build.metadataSource,
unavailableReason: manager.build.unavailableReason,
unavailableDetail: manager.build.unavailableDetail,
liveMetadataMatch: manager.build.liveMetadataMatch,
counts: payload.counts
};
};
assert.deepEqual(summarize(withOldReport), summarize(withoutOldReport));
const manager = withOldReport.services.find((service) => service.serviceId === "hwlab-device-pod");
assert.equal(withOldReport.latest, null);
assert.equal(manager.build.createdAt, null);
assert.equal(Object.hasOwn(withOldReport.source, "artifactReportSource"), false);
assert.equal(JSON.stringify(withOldReport).includes("2099-01-01T00:00:00.000Z"), false);
assert.equal(JSON.stringify(withOldReport).includes("artifact-report"), false);
} finally {
await rm(tempRoot, { recursive: true, force: true });
}
});