ouroboros/tests/test_platform_ci_events.py

103 lines
4.7 KiB
Python

"""Ordinary desktop PR coverage at the existing CI matrix/event seam."""
from __future__ import annotations
import json
import re
from pathlib import Path
from types import SimpleNamespace
import pytest
import yaml
ROOT = Path(__file__).resolve().parents[1]
WORKFLOW = yaml.safe_load((ROOT / ".github/workflows/ci.yml").read_text(encoding="utf-8"))
def _value(expression, *, event, ref, base="", schedule="", cancelled=False):
"""Evaluate the workflow's small expression vocabulary against real event shapes."""
expression = expression.strip()
if expression.startswith("$" + "{{"):
expression = expression[3:-2]
expression = " ".join(expression.split()).replace("&&", " and ").replace("||", " or ")
expression = re.sub(r"!(?!=)", "not ", expression)
github = SimpleNamespace(
event_name=event, ref=ref, base_ref=base,
event=SimpleNamespace(
schedule=schedule, inputs=SimpleNamespace(e2e_live="false"), before="previous-tip",
pull_request=SimpleNamespace(base=SimpleNamespace(sha="pr-base")),
),
)
return eval(expression, {"__builtins__": {}}, {
"github": github, "fromJSON": json.loads,
"startsWith": lambda value, prefix: value.startswith(prefix),
"always": lambda: True, "cancelled": lambda: cancelled,
})
@pytest.mark.parametrize("event,ref,base,quick,platforms", [
("pull_request", "refs/pull/42/merge", "ouroboros", True, ["windows-latest", "macos-latest"]),
("pull_request", "refs/pull/42/merge", "main", False, []),
("push", "refs/heads/ouroboros", "", True, []),
("push", "refs/heads/main", "", False, []),
("push", "refs/heads/ouroboros-stable", "", False, ["ubuntu-latest", "windows-latest", "macos-latest"]),
("push", "refs/tags/v7.0.0", "", False, ["ubuntu-latest", "windows-latest", "macos-latest"]),
("workflow_dispatch", "refs/heads/candidate", "", True, ["ubuntu-latest", "windows-latest", "macos-latest"]),
("schedule", "refs/heads/main", "", False, []),
])
def test_ordinary_matrix_expands_for_prs_without_changing_existing_events(event, ref, base, quick, platforms):
facts = {"event": event, "ref": ref, "base": base}
assert bool(_value(WORKFLOW["jobs"]["quick-test"]["if"], **facts)) is quick
job = WORKFLOW["jobs"]["full-test"]
admitted = _value(job["if"], **facts)
actual = _value(job["strategy"]["matrix"]["os"], **facts) if admitted else []
assert actual == platforms
assert job["strategy"]["fail-fast"] is False
assert job["runs-on"] == "$" + "{{ matrix.os }}"
def test_desktop_pr_matrix_keeps_merge_checkout_and_pr_base_evidence_secret_free():
triggers = WORKFLOW.get("on") or WORKFLOW[True] # PyYAML's YAML 1.1 spelling of "on".
assert triggers["pull_request"]["branches"] == ["ouroboros"]
assert "pull_request_target" not in triggers
assert WORKFLOW["permissions"] == {"contents": "read"}
job = WORKFLOW["jobs"]["full-test"]
assert "secrets." not in json.dumps(job)
assert not job.get("permissions")
checkout = job["steps"][0]
assert checkout["uses"] == "actions/checkout@v4"
assert checkout["with"] == {"fetch-depth": 0} # Default PR checkout tests the merge ref.
base = next(step["env"]["OURO_SIZE_RATCHET_BASE_REF"] for step in job["steps"]
if "OURO_SIZE_RATCHET_BASE_REF" in step.get("env", {}))
assert _value(base, event="pull_request", ref="refs/pull/42/merge", base="ouroboros") == "pr-base"
assert _value(base, event="push", ref="refs/heads/ouroboros-stable") == "previous-tip"
@pytest.mark.parametrize("cron", ["37 4 * * *", "17 3 * * *"])
def test_scheduled_main_runs_do_not_enter_the_ordinary_matrix(cron):
for name in ("quick-test", "full-test"):
assert not _value(
WORKFLOW["jobs"][name]["if"], event="schedule", ref="refs/heads/main", schedule=cron,
)
@pytest.mark.parametrize("name", [
"integration-test", "skill-smoke", "system-e2e-mock", "e2e-live",
"marker-guards", "docker-ui-smoke", "docker-portable-test",
"release-preflight", "build", "release", "vendor-package-smoke",
])
def test_desktop_pr_coverage_does_not_admit_provider_or_release_jobs(name):
job = WORKFLOW["jobs"][name]
assert not _value(job["if"], event="pull_request", ref="refs/pull/42/merge", base="ouroboros")
@pytest.mark.parametrize(("event", "cancelled", "expected"), [
("pull_request", False, True), ("pull_request", True, False),
("schedule", False, False), ("schedule", True, False),
])
def test_status_checks_and_inequality_keep_independent_meanings(event, cancelled, expected):
assert _value(
"${{ always() && !cancelled() && github.event_name != 'schedule' }}",
event=event, ref="refs/heads/candidate", cancelled=cancelled,
) is expected