154 lines
8.8 KiB
TypeScript
154 lines
8.8 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { resolve } from "node:path";
|
|
|
|
import { renderPikaoaTestDesiredPipeline } from "./pikaoa-test-delivery-renderer";
|
|
|
|
function pacDocument(): Record<string, unknown> {
|
|
return Bun.YAML.parse(readFileSync(resolve(import.meta.dir, "../../config/platform-infra/pipelines-as-code.yaml"), "utf8")) as Record<string, unknown>;
|
|
}
|
|
|
|
function rendererBinding(id = "pikaoa-test-nc01"): Parameters<typeof renderPikaoaTestDesiredPipeline>[0] {
|
|
const document = pacDocument();
|
|
const repositories = document.repositories as Array<Record<string, unknown>>;
|
|
const consumers = document.consumers as Array<Record<string, unknown>>;
|
|
const consumer = consumers.find((item) => item.id === id);
|
|
const repository = repositories.find((item) => item.id === consumer?.repositoryRef);
|
|
if (repository === undefined || consumer === undefined) throw new Error(`PikaOA PaC fixture is required: ${id}`);
|
|
return {
|
|
consumer,
|
|
repository: {
|
|
...repository,
|
|
params: {
|
|
...(repository.params as Record<string, unknown>),
|
|
...((consumer.params as Record<string, unknown> | undefined) ?? {}),
|
|
},
|
|
},
|
|
} as Parameters<typeof renderPikaoaTestDesiredPipeline>[0];
|
|
}
|
|
|
|
function sourceFixture(): string {
|
|
const root = mkdtempSync(resolve(tmpdir(), "pikaoa-test-renderer-"));
|
|
mkdirSync(resolve(root, "deploy"), { recursive: true });
|
|
for (const file of ["api.Dockerfile", "worker.Dockerfile", "web.Dockerfile"]) writeFileSync(resolve(root, "deploy", file), "FROM scratch\n");
|
|
return root;
|
|
}
|
|
|
|
describe("PikaOA test PaC renderer", () => {
|
|
test("shares one PaC repository while isolating master and release consumers", () => {
|
|
const document = pacDocument();
|
|
const repositories = document.repositories as Array<Record<string, unknown>>;
|
|
const consumers = document.consumers as Array<Record<string, unknown>>;
|
|
const repository = repositories.find((item) => item.id === "pikaoa-test-nc01");
|
|
const testConsumer = consumers.find((item) => item.id === "pikaoa-test-nc01");
|
|
const productionConsumer = consumers.find((item) => item.id === "pikaoa-nc01");
|
|
const duplicateProductionRepository = repositories.find((item) => item.id === "pikaoa-nc01");
|
|
expect((repository?.params as Record<string, unknown>).source_branch).toBe("master");
|
|
expect((testConsumer?.sourceArtifact as Record<string, unknown>).pipelineRunPath).toBe(".tekton/pikaoa-test-nc01-pac.yaml");
|
|
expect((testConsumer?.sourceArtifact as Record<string, unknown>).renderer).toBe("pikaoa-test-runtime");
|
|
expect((productionConsumer?.params as Record<string, unknown>).source_branch).toBe("release");
|
|
expect((productionConsumer?.params as Record<string, unknown>).source_snapshot_prefix).toBe("refs/unidesk/snapshots/gitea-actions/pikaoa-release-nc01");
|
|
expect(productionConsumer?.repositoryRef).toBe("pikaoa-test-nc01");
|
|
expect(duplicateProductionRepository).toBeUndefined();
|
|
expect((productionConsumer?.sourceArtifact as Record<string, unknown>).renderer).toBe("pikaoa-release-runtime");
|
|
expect((productionConsumer?.sourceArtifact as Record<string, unknown>).configRef).toBe("config/pikaoa.yaml#releaseRuntime.targets.NC01");
|
|
});
|
|
|
|
test("renders release runtime from its isolated owning selector", () => {
|
|
const source = sourceFixture();
|
|
try {
|
|
const rendered = renderPikaoaTestDesiredPipeline(rendererBinding("pikaoa-nc01"), source);
|
|
expect(rendered.configRef).toBe("config/pikaoa.yaml#releaseRuntime.targets.NC01");
|
|
const serialized = JSON.stringify(rendered.pipeline);
|
|
expect(serialized).toContain("pikaoa-nc01-pac");
|
|
expect(serialized).toContain("refs/unidesk/snapshots/gitea-actions/pikaoa-release-nc01");
|
|
expect(serialized).toContain("pac-gitea-pikaoa-nc01");
|
|
expect(serialized).not.toContain("pikaoa-test-nc01-pac");
|
|
} finally {
|
|
rmSync(source, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("renders parallel digest builds and a PreSync fresh database initializer", () => {
|
|
const source = sourceFixture();
|
|
try {
|
|
const rendered = renderPikaoaTestDesiredPipeline(rendererBinding(), source);
|
|
const spec = rendered.pipeline.spec as Record<string, unknown>;
|
|
const tasks = spec.tasks as Array<Record<string, unknown>>;
|
|
for (const task of tasks) {
|
|
const taskSpec = task.taskSpec as Record<string, unknown>;
|
|
expect(taskSpec.workspaces).toEqual([{ name: "workspace", mountPath: "/workspace" }]);
|
|
const steps = taskSpec.steps as Array<Record<string, unknown>>;
|
|
for (const step of steps) {
|
|
const mounts = (step.volumeMounts ?? []) as Array<Record<string, unknown>>;
|
|
expect(mounts.some((mount) => mount.name === "workspace")).toBe(false);
|
|
}
|
|
}
|
|
for (const name of ["build-api", "build-worker", "build-web"]) {
|
|
const task = tasks.find((item) => item.name === name);
|
|
expect(task?.runAfter).toEqual(["source"]);
|
|
expect(JSON.stringify(task)).toContain("buildctl-daemonless.sh build");
|
|
expect(JSON.stringify(task)).toContain("$(params.revision)");
|
|
expect(JSON.stringify(task)).not.toContain("source-token");
|
|
const buildScript = (((task?.taskSpec as Record<string, unknown>).steps as Array<Record<string, unknown>>)[0]?.script) as string;
|
|
expect(buildScript).toContain('"containerimage.digest"[[:space:]]*:[[:space:]]*"\\(sha256:[0-9a-f]\\{64\\}\\)"');
|
|
expect(buildScript).toContain(".*/\\1/p");
|
|
expect(buildScript).not.toContain("\u0001");
|
|
expect(buildScript).toContain("Docker-Content-Digest:");
|
|
expect(buildScript).toContain("build_status=$?");
|
|
expect(buildScript).toContain('"code":"buildctl-nonzero-artifact-verified"');
|
|
expect(buildScript).toContain('"artifactVerified":true');
|
|
}
|
|
const digest = "sha256:" + "a".repeat(64);
|
|
const metadata = JSON.stringify({ "containerimage.digest": digest }, null, 2);
|
|
const parsedDigest = /"containerimage\.digest"\s*:\s*"(sha256:[0-9a-f]{64})"/u.exec(metadata)?.[1];
|
|
expect(parsedDigest).toBe(digest);
|
|
const sourceTask = tasks.find((item) => item.name === "source");
|
|
expect(JSON.stringify(sourceTask)).toContain("source-token");
|
|
expect(JSON.stringify(sourceTask)).toContain("GIT_ASKPASS");
|
|
expect(JSON.stringify(sourceTask)).toContain("$(params.gitops-secret-name)");
|
|
for (const task of tasks) {
|
|
const taskSpec = task.taskSpec as Record<string, unknown> | undefined;
|
|
if (taskSpec === undefined) continue;
|
|
expect(taskSpec.workspaces).toEqual([{ name: "workspace", mountPath: "/workspace" }]);
|
|
const steps = taskSpec.steps as Array<Record<string, unknown>>;
|
|
for (const step of steps) {
|
|
expect((step.volumeMounts as Array<Record<string, unknown>> | undefined)?.some((mount) => mount.name === "workspace") ?? false).toBe(false);
|
|
}
|
|
}
|
|
const publish = tasks.find((item) => item.name === "gitops-publish");
|
|
expect(publish?.runAfter).toEqual(["build-api", "build-worker", "build-web"]);
|
|
const script = ((((publish?.taskSpec as Record<string, unknown>).steps as Array<Record<string, unknown>>)[0]?.script) as string);
|
|
for (const evidence of [
|
|
'"status":"published"',
|
|
'"registryVerified":true',
|
|
'"publishedCount":3',
|
|
'"requiredServiceCount":3',
|
|
'"gitopsCommit"',
|
|
'"service":"api"',
|
|
'"service":"worker"',
|
|
'"service":"web"',
|
|
]) expect(script).toContain(evidence);
|
|
const encoded = /printf '%s' '([A-Za-z0-9+/=]+)' \| base64 -d/u.exec(script)?.[1];
|
|
if (encoded === undefined) throw new Error("embedded GitOps manifest is required");
|
|
const manifest = Buffer.from(encoded, "base64").toString("utf8");
|
|
expect(manifest).toContain("argocd.argoproj.io/hook: PreSync");
|
|
expect(manifest).toContain("name: pikaoa-init");
|
|
expect(manifest).toContain("name: initializer");
|
|
expect(manifest).not.toContain("kind: Secret");
|
|
expect(manifest).toContain("secretName: pikaoa-test-runtime");
|
|
expect(manifest).toContain("image: __PIKAOA_API_IMAGE__");
|
|
expect(manifest).toContain("pikaoa.unidesk.io/source-commit: __PIKAOA_SOURCE_COMMIT__");
|
|
expect(script).toContain('s|__PIKAOA_SOURCE_COMMIT__|$SOURCE_COMMIT|g');
|
|
expect(script).toContain("GitOps manifest contains unresolved provenance or image placeholders");
|
|
expect(script).not.toContain("grep -Eq '$(params.revision)");
|
|
expect(script).toContain("grep -Eq '__PIKAOA_SOURCE_COMMIT__|__PIKAOA_(API|WORKER|WEB)_IMAGE__'");
|
|
expect(script).toContain("git ls-remote --exit-code --heads");
|
|
expect(script).toContain("git -C /workspace/gitops checkout --orphan");
|
|
} finally {
|
|
rmSync(source, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|