106 lines
4.8 KiB
TypeScript
106 lines
4.8 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { buildProviderTriageResult, compactProviderTriageResult, type ProviderTriageSignal } from "./provider-triage";
|
|
|
|
function signal(
|
|
id: string,
|
|
scope: ProviderTriageSignal["scope"],
|
|
status: ProviderTriageSignal["status"],
|
|
): ProviderTriageSignal {
|
|
return {
|
|
id,
|
|
scope,
|
|
status,
|
|
independentPath: true,
|
|
observedAt: "2026-05-20T00:00:00.000Z",
|
|
summary: `${id}:${scope}:${status}`,
|
|
};
|
|
}
|
|
|
|
describe("provider triage contract", () => {
|
|
test("single path provider offline stays non-global blocker", () => {
|
|
const result = buildProviderTriageResult("D601", [
|
|
signal("runner-local", "runner-local", "failed"),
|
|
signal("backend-core-node", "provider-gateway", "ok"),
|
|
signal("host-ssh-probe", "ssh", "ok"),
|
|
], "2026-05-20T00:00:00.000Z");
|
|
|
|
expect(result.blockingDisposition).toBe("runner-local-observation-gap");
|
|
expect(result.decision).toBe("retryable-transient");
|
|
expect(result.retryable).toBe(true);
|
|
expect(result.scope).toBe("runner-local");
|
|
expect(result.failedScopes).toContain("runner-local");
|
|
expect(result.contract.singlePathProviderOfflineIsGlobalBlocker).toBe(false);
|
|
});
|
|
|
|
test("multiple independent critical failures can global block", () => {
|
|
const result = buildProviderTriageResult("D601", [
|
|
signal("backend-core-node", "provider-gateway", "failed"),
|
|
signal("host-ssh-probe", "ssh", "failed"),
|
|
signal("code-queue-health", "scheduler", "failed"),
|
|
], "2026-05-20T00:00:00.000Z");
|
|
|
|
expect(result.blockingDisposition).toBe("global-blocker");
|
|
expect(result.decision).toBe("global-offline");
|
|
expect(result.retryable).toBe(false);
|
|
expect(result.failedIndependentScopes).toContain("provider-gateway");
|
|
expect(result.failedIndependentScopes).toContain("ssh");
|
|
});
|
|
|
|
test("registry failure with healthy heartbeat and ssh is degraded, not global blocker", () => {
|
|
const result = buildProviderTriageResult("D601", [
|
|
signal("backend-core-node", "provider-gateway", "ok"),
|
|
signal("host-ssh-probe", "ssh", "ok"),
|
|
signal("artifact-registry-health", "registry", "failed"),
|
|
signal("k3sctl-adapter-health", "k3s", "ok"),
|
|
], "2026-05-20T00:00:00.000Z");
|
|
|
|
expect(result.blockingDisposition).toBe("service-degraded");
|
|
expect(result.decision).toBe("service-degraded");
|
|
expect(result.retryable).toBe(true);
|
|
expect(result.failedScopes).toContain("registry");
|
|
expect(result.healthyScopes).toContain("provider-gateway");
|
|
expect(result.healthyIndependentScopes).toContain("provider-gateway");
|
|
expect(result.healthyIndependentScopes).toContain("ssh");
|
|
});
|
|
|
|
test("registry systemd inactive with listener and api healthy is service degraded", () => {
|
|
const result = buildProviderTriageResult("D601", [
|
|
signal("backend-core-node", "provider-gateway", "ok"),
|
|
signal("host-ssh-probe", "ssh", "ok"),
|
|
signal("artifact-registry-health", "registry", "degraded"),
|
|
signal("k3sctl-adapter-health", "k3s", "ok"),
|
|
], "2026-05-20T00:00:00.000Z");
|
|
|
|
expect(result.decision).toBe("service-degraded");
|
|
expect(result.blockingDisposition).toBe("service-degraded");
|
|
expect(result.retryable).toBe(true);
|
|
expect(result.degradedScopes).toContain("registry");
|
|
expect(result.healthyScopes).toEqual(expect.arrayContaining(["k3s", "provider-gateway", "ssh"]));
|
|
});
|
|
|
|
test("compact output is bounded and preserves drill-down command args", () => {
|
|
const result = buildProviderTriageResult("D601", [
|
|
signal("backend-core-node", "provider-gateway", "ok"),
|
|
signal("host-ssh-probe", "ssh", "ok"),
|
|
signal("artifact-registry-health", "registry", "degraded"),
|
|
signal("k3sctl-adapter-health", "k3s", "unknown"),
|
|
signal("code-queue-health", "scheduler", "unknown"),
|
|
signal("service-a", "microservice", "failed"),
|
|
signal("service-b", "microservice", "failed"),
|
|
signal("service-c", "microservice", "degraded"),
|
|
signal("service-d", "microservice", "unknown"),
|
|
signal("service-e", "microservice", "unknown"),
|
|
signal("service-f", "microservice", "unknown"),
|
|
], "2026-05-20T00:00:00.000Z");
|
|
|
|
const compact = compactProviderTriageResult(result, ["--microservice", "code-queue", "--microservice", "k3sctl-adapter"]);
|
|
const signalCounts = compact.signalCounts as Record<string, unknown>;
|
|
const outputPolicy = compact.outputPolicy as Record<string, unknown>;
|
|
|
|
expect((compact.signals as unknown[]).length).toBe(8);
|
|
expect(signalCounts.omittedIssueSignals).toBe(1);
|
|
expect(outputPolicy.full).toBe("bun scripts/cli.ts provider triage D601 --microservice 'code-queue' --microservice 'k3sctl-adapter' --full");
|
|
expect(outputPolicy.raw).toBe("bun scripts/cli.ts provider triage D601 --microservice 'code-queue' --microservice 'k3sctl-adapter' --raw");
|
|
});
|
|
});
|