Files
pikasTech-unidesk/scripts/code-queue-issue3-regression-test.ts
T

107 lines
5.0 KiB
TypeScript

import { readFileSync } from "node:fs";
import { codeQueueContainerdImagePreflight, codeQueueManifestImagePreflight } from "./src/deploy";
type JsonRecord = Record<string, unknown>;
function assertCondition(condition: unknown, message: string, detail: JsonRecord = {}): void {
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}
function gatewayCheck(diagnostics: JsonRecord): JsonRecord {
const checks = diagnostics.checks as JsonRecord | undefined;
const deployment = checks?.deployment as JsonRecord | undefined;
const endpoint = checks?.endpoint as JsonRecord | undefined;
const target = checks?.targetService as JsonRecord | undefined;
const deploymentAvailable = deployment?.available === true;
const endpointNonEmpty = Number(endpoint?.readyAddressCount ?? 0) > 0;
return {
ok: diagnostics.ok === true && deploymentAvailable && endpointNonEmpty && target?.ok === true,
deploymentAvailable,
endpointNonEmpty,
targetServiceOk: target?.ok === true,
};
}
function schedulerStorageCheck(schedulerHealth: JsonRecord): JsonRecord {
const queue = schedulerHealth.queue as JsonRecord | undefined;
const storage = queue?.storage as JsonRecord | undefined;
const lastError = storage?.lastError ?? null;
return {
ok: storage?.postgresReady === true && lastError === null,
postgresReady: storage?.postgresReady === true,
lastError,
};
}
function staleReconcileCheck(schedulerHealth: JsonRecord): JsonRecord {
const queue = schedulerHealth.queue as JsonRecord | undefined;
const reconcile = queue?.reconcile as JsonRecord | undefined;
const recoverable = Number(reconcile?.recoverableOrphanedActiveTaskCount ?? queue?.orphanedActiveTaskCount ?? 0);
return {
ok: recoverable === 0,
recoverableOrphanedActiveTaskCount: recoverable,
retryWaitTaskCount: Number(reconcile?.retryWaitTaskCount ?? 0),
};
}
function runIssue3Regression(): JsonRecord {
const missingEndpointGateway = gatewayCheck({
ok: false,
checks: {
deployment: { ok: true, available: true, availableReplicas: 1 },
endpoint: { ok: false, readyAddressCount: 0 },
targetService: { ok: false },
},
});
assertCondition(missingEndpointGateway.ok === false, "microservice:code-queue-egress-gateway-health must fail on empty endpoint", missingEndpointGateway);
assertCondition(missingEndpointGateway.deploymentAvailable === true, "gateway deployment availability should be reported separately", missingEndpointGateway);
assertCondition(missingEndpointGateway.endpointNonEmpty === false, "gateway endpoint non-empty check should be explicit", missingEndpointGateway);
const storageFailure = schedulerStorageCheck({
queue: {
storage: {
postgresReady: false,
lastError: "CONNECT_TIMEOUT d601-tcp-egress-gateway.unidesk.svc.cluster.local:15432",
},
},
});
assertCondition(storageFailure.ok === false, "diagnostics must fail when scheduler storage.lastError reports PostgreSQL route failure", storageFailure);
assertCondition(String(storageFailure.lastError).includes("CONNECT_TIMEOUT"), "storage failure detail should preserve route error", storageFailure);
const staleReconcile = staleReconcileCheck({
queue: {
orphanedActiveTaskCount: 1,
reconcile: {
recoverableOrphanedActiveTaskCount: 1,
retryWaitTaskCount: 2,
},
},
});
assertCondition(staleReconcile.ok === false, "code-queue:stale-active-reconcile must fail while recoverable active tasks remain", staleReconcile);
assertCondition(staleReconcile.retryWaitTaskCount === 2, "retry_wait reconcile count should be visible", staleReconcile);
const missingImage = codeQueueContainerdImagePreflight("docker.io/library/busybox:latest\n", "unidesk-code-queue:d601");
assertCondition(missingImage.ok === false, "code-queue:containerd-image-preflight must fail when k3s containerd lacks unidesk-code-queue:d601", missingImage);
const presentImage = codeQueueContainerdImagePreflight("docker.io/library/busybox:latest\nunidesk-code-queue:d601 application/vnd.oci.image.manifest.v1+json\n", "unidesk-code-queue:d601");
assertCondition(presentImage.ok === true, "code-queue:containerd-image-preflight should pass when the tag is present", presentImage);
const manifestPath = "src/components/microservices/k3sctl-adapter/k3s/code-queue.k8s.yaml";
const manifest = readFileSync(manifestPath, "utf8");
const manifestImage = codeQueueManifestImagePreflight(manifest, "unidesk-code-queue:d601");
assertCondition(manifestImage.ok === true, "Code Queue k8s manifest deployments must all use unidesk-code-queue:d601", manifestImage);
return {
ok: true,
checks: [
{ name: "microservice:code-queue-egress-gateway-health", ok: true },
{ name: "microservice:code-queue-postgres-route-health", ok: true },
{ name: "code-queue:containerd-image-preflight", ok: true },
{ name: "code-queue:stale-active-reconcile", ok: true },
],
};
}
if (import.meta.main) {
process.stdout.write(`${JSON.stringify(runIssue3Regression(), null, 2)}\n`);
}