Files
projectbrain-Public/backend/test/native-ci-discovery.test.ts
T

79 lines
4.8 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { GiteaClient } from "../src/integrations/gitea/client.js";
import { assertSuccessfulActionRuns, exactHeadActionRuns } from "../src/integrations/gitea/policy.js";
import type { GiteaActionRun } from "../src/integrations/gitea/types.js";
const branch = "codex/native-ci";
const sha = "a".repeat(40);
const context = "CI / build-test (pull_request)";
const run = (id: number, overrides: Partial<GiteaActionRun> = {}): GiteaActionRun => ({
id, run_number: id, display_title: "Managed validation / full", path: ".gitea/workflows/managed-validation.yml",
event: "pull_request", head_sha: sha, head_branch: "", status: "completed",
conclusion: "success", html_url: `https://gitea.example/runs/${id}`, ...overrides,
});
describe("native PR validation discovery", () => {
it("discovers an empty branch by exact SHA and checks available PR identity", () => {
const matching = run(1, { pull_requests: [{ number: 30, head: { ref: branch, sha } }] });
expect(exactHeadActionRuns([
matching, run(2), run(3, { head_sha: "stale" }),
run(4, { head_branch: "other" }),
run(5, { pull_requests: [{ number: 31, head: { ref: "other", sha } }] }),
run(6, { event: "workflow_dispatch" }),
], branch, sha)).toEqual([matching, run(2)]);
expect(assertSuccessfulActionRuns([matching], branch, sha)).toEqual([matching]);
});
it.each(["pending", "queued", "waiting", "in_progress"])("does not authorize %s", (status) => {
expect(() => assertSuccessfulActionRuns([run(1, { status, conclusion: undefined })], branch, sha)).toThrow("FEATURE_DELIVERY_FULL_VALIDATION_REQUIRED");
});
it.each(["cancelled", "canceled", "failure"])("does not authorize a %s job that never started", (conclusion) => {
expect(() => assertSuccessfulActionRuns([run(1, { conclusion })], branch, sha)).toThrow("FEATURE_DELIVERY_FULL_VALIDATION_REQUIRED");
});
it("uses the newest attempt of each workflow and preserves all evidence", () => {
const failure = run(2, { conclusion: "failure" });
expect(() => assertSuccessfulActionRuns([failure, run(1, { status: "pending" })], branch, sha)).toThrow();
const success = run(3);
expect(assertSuccessfulActionRuns([failure, success], branch, sha)).toEqual([failure, success]);
expect(() => assertSuccessfulActionRuns([success, run(4, { status: "queued" })], branch, sha)).toThrow();
});
it("never lets dispatch success replace PR failure even for the same workflow path", () => {
expect(() => assertSuccessfulActionRuns([
run(1, { conclusion: "failure" }),
run(2, { event: "workflow_dispatch", head_branch: branch }),
], branch, sha)).toThrow("FEATURE_DELIVERY_CI_NOT_SUCCESSFUL");
});
it("queries by exact SHA without the upstream branch filter", async () => {
const fetcher = vi.fn(async () => new Response(JSON.stringify({ total_count: 1, workflow_runs: [run(1)] })));
await new GiteaClient("https://gitea.example", "test-only", fetcher as typeof fetch).listActionRuns("Jens", "Repo", { branch, headSha: sha });
const url = new URL(String(fetcher.mock.calls[0]![0]));
expect(url.searchParams.get("head_sha")).toBe(sha);
expect(url.searchParams.has("branch")).toBe(false);
});
it.each([
[[{ context, status: "failure" }, { context, status: "pending" }], "GITEA_REQUIRED_CHECKS_FAILED"],
[[{ context: "CI / build-test (workflow_dispatch)", status: "success" }], "GITEA_REQUIRED_CHECKS_PENDING"],
[[{ context: `${context} extra`, status: "success" }], "GITEA_REQUIRED_CHECKS_PENDING"],
[[{ context, status: "pending" }], "GITEA_REQUIRED_CHECKS_PENDING"],
] as const)("requires the exact latest protected status %#", async (statuses, error) => {
const fetcher = vi.fn(async (url: URL | RequestInfo) => new Response(JSON.stringify(String(url).includes("branch_protections")
? { enable_status_check: true, status_check_contexts: [context] } : { statuses })));
const client = new GiteaClient("https://gitea.example", "test-only", fetcher as typeof fetch);
await expect(client.waitForRequiredPullRequestChecks("Jens", "Repo", "main", sha, { timeoutMs: 0 })).rejects.toMatchObject({ code: error });
expect(String(fetcher.mock.calls[1]![0])).toContain(`/commits/${sha}/status`);
});
it("accepts a newer native success after an old native failure", async () => {
const fetcher = vi.fn(async (url: URL | RequestInfo) => new Response(JSON.stringify(String(url).includes("branch_protections")
? { enable_status_check: true, status_check_contexts: [context] }
: { statuses: [{ context, status: "success" }, { context, status: "failure" }] })));
await expect(new GiteaClient("https://gitea.example", "test-only", fetcher as typeof fetch)
.waitForRequiredPullRequestChecks("Jens", "Repo", "main", sha, { timeoutMs: 0 })).resolves.toMatchObject({ state: "success" });
});
});