Files
pikasTech-unidesk/scripts/src/platform-infra-pac-failure-evidence.test.ts
T

91 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, test } from "bun:test";
import { spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { createRequire } from "node:module";
import { sentinelPublishImageBuildShell } from "./hwlab-node-web-sentinel-cicd-jobs";
import type { SentinelCicdState } from "./hwlab-node-web-sentinel-cicd-shared";
import { compactHistoryJson, compactStatusSummary, renderDebugStep, renderHistory, renderStatus } from "./platform-infra-pipelines-as-code";
const require = createRequire(import.meta.url);
const { parsePacLogRecords } = require("../native/cicd/pac-status-evaluator.cjs") as {
parsePacLogRecords(value: string): Array<Record<string, unknown>>;
};
describe("PaC 失败证据合同", () => {
test("真实 sentinel TaskRun 日志保留 typed 首断点", () => {
const fixture = resolve(import.meta.dir, "fixtures/pac/hwlab-web-probe-sentinel-nc01-r5ww2.log");
const record = parsePacLogRecords(readFileSync(fixture, "utf8")).find((item) => item.ok === false);
expect(record).toMatchObject({
traceId: "6e6e899d3e812891140aedfd974d524e",
firstBreak: { code: "child-process-exit-nonzero", phase: "image-build" },
error: { type: "ChildProcessError", code: "EXIT_NONZERO", phase: "image-build", exitCode: 1 },
});
});
test("history、debug-step、status 默认显示 typed 失败字段", () => {
const fixture = resolve(import.meta.dir, "fixtures/pac/hwlab-web-probe-sentinel-nc01-r5ww2.log");
const failure = parsePacLogRecords(readFileSync(fixture, "utf8")).find((item) => item.ok === false) ?? {};
const row = {
id: "hwlab-web-probe-sentinel-nc01-r5ww2",
consumer: "sentinel-nc01-v03",
deliveryClass: "outer-pac-event",
status: "False",
traceId: failure.traceId,
firstBreak: failure.firstBreak,
error: failure.error,
};
const history = renderHistory({ rows: [row], config: {}, historyErrors: [], next: {} }).renderedText;
const debug = renderDebugStep({ realRun: { found: true, pipelineRun: row, firstBreak: row.firstBreak, error: row.error, traceId: row.traceId }, checks: [], target: {}, next: {} }).renderedText;
const status = renderStatus({ summary: { latestPipelineRun: row, artifact: row, diagnostics: {} }, consumer: {}, deliveryAuthority: {}, config: {}, coverage: [], target: {}, next: {} }).renderedText;
for (const output of [history, debug, status]) {
expect(output).toContain("6e6e899d3e8128");
expect(output).toContain("child-process-exit-nonzero");
expect(output).toContain("ChildProcessError");
expect(output).toContain("image-build");
expect(output).toContain("EXIT_NONZERO");
expect(output).toContain("1");
}
const compactHistory = compactHistoryJson({ rows: [{ ...row, collector: { matchingTaskCount: 1 } }], detailId: row.id });
const compactStatus = compactStatusSummary({ latestPipelineRun: row, artifact: row });
expect(compactHistory).toMatchObject({ rows: [{ traceId: row.traceId, firstBreak: row.firstBreak, error: row.error, collector: { matchingTaskCount: 1 } }] });
expect(compactStatus).toMatchObject({ artifact: { traceId: row.traceId, firstBreak: row.firstBreak, error: row.error } });
});
test("collector 遍历全部 matching TaskRunterminal record 仍限定合同任务", () => {
const remote = readFileSync(resolve(import.meta.dir, "platform-infra-pipelines-as-code-remote.sh"), "utf8");
expect(remote).toContain("for (const item of matching)");
expect(remote).toContain("const contractTaskRuns = matching.filter((item) => taskTerminalRecord(item) !== null)");
expect(remote).toContain("Object.keys(record(row.firstBreak)).length > 0");
expect(remote).toContain("traceId: row.traceId || null");
});
test("sentinel image build 显式等待 socket 与 worker readiness 并清理 daemon", () => {
const shell = sentinelPublishImageBuildShell({
spec: {
nodeId: "NC01",
lane: "v03",
buildkit: { sidecarImage: "moby/buildkit:rootless" },
networkProfile: { imageBuildProxy: { http: "", https: "", all: "", noProxy: [] } },
},
image: {
ref: "registry.example.test/web-probe-sentinel:test",
monitorWeb: {
imageBuildPackageMode: "frozen-lockfile",
imageBuildNetworkMode: "host",
imageBuildProxySource: "test",
},
},
} as unknown as SentinelCicdState, "sentinel-test");
expect(shell).toContain("mkdir -p \"$(dirname \"$buildkit_socket\")\"");
expect(shell).toContain("rootlesskit buildkitd --addr");
expect(shell).not.toMatch(/(^|\n)buildkitd --addr/);
expect(shell).toContain("debug workers");
expect(shell).toContain("failure_error_type=BuildKitReadinessError");
expect(shell).toContain("failure_error_code=BUILDKIT_NOT_READY");
expect(shell).toContain("cleanup_buildkitd");
expect(shell).not.toContain("buildctl-daemonless.sh build");
expect(spawnSync("sh", ["-n"], { input: shell, encoding: "utf8" })).toMatchObject({ status: 0, stderr: "" });
});
});