108 lines
4.1 KiB
Python
108 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Contract tests for the prebuilt desktop E2E image path."""
|
|
|
|
from pathlib import Path
|
|
import unittest
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
DOCKERFILE = REPO_ROOT / ".github" / "docker" / "ci-base" / "Dockerfile"
|
|
IMAGE_WORKFLOW = REPO_ROOT / ".github" / "workflows" / "ci-base-image.yml"
|
|
E2E_WORKFLOW = REPO_ROOT / ".github" / "workflows" / "e2e-tests.yml"
|
|
LINT_WORKFLOW = REPO_ROOT / ".github" / "workflows" / "lint-action-pinning.yml"
|
|
|
|
|
|
def job_block(workflow: str, job: str, next_job: str) -> str:
|
|
"""Return one workflow job block without parsing YAML anchors or expressions."""
|
|
marker = f" {job}:\n"
|
|
_, separator, remainder = workflow.partition(marker)
|
|
if not separator:
|
|
raise AssertionError(f"Workflow has no {job} job")
|
|
return remainder.partition(f"\n {next_job}:\n")[0]
|
|
|
|
|
|
class DesktopE2EWorkflowContractTest(unittest.TestCase):
|
|
def test_desktop_image_contains_pinned_toolchain_and_system_dependencies(self) -> None:
|
|
dockerfile = DOCKERFILE.read_text(encoding="utf-8")
|
|
|
|
self.assertIn("FROM runtime AS desktop", dockerfile)
|
|
self.assertIn("ARG RUST_VERSION=1.97.1", dockerfile)
|
|
self.assertIn("rustup toolchain install \"${RUST_VERSION}\" --profile minimal", dockerfile)
|
|
|
|
for package in (
|
|
"build-essential",
|
|
"pkg-config",
|
|
"libglib2.0-dev",
|
|
"libwebkit2gtk-4.1-dev",
|
|
"libgtk-3-dev",
|
|
"libayatana-appindicator3-dev",
|
|
"librsvg2-dev",
|
|
"patchelf",
|
|
"rpm",
|
|
"xvfb",
|
|
):
|
|
self.assertIn(package, dockerfile)
|
|
|
|
for smoke_command in (
|
|
"rustc --version",
|
|
"cargo --version",
|
|
"pkg-config --exists webkit2gtk-4.1",
|
|
"command -v patchelf",
|
|
"command -v xvfb-run",
|
|
):
|
|
self.assertIn(smoke_command, dockerfile)
|
|
|
|
def test_image_workflow_publishes_desktop_tags(self) -> None:
|
|
workflow = IMAGE_WORKFLOW.read_text(encoding="utf-8")
|
|
|
|
self.assertIn("target: desktop", workflow)
|
|
self.assertIn("desktop-sha-${{ steps.tag.outputs.image_tag }}", workflow)
|
|
self.assertIn("${{ env.IMAGE_NAME }}:desktop-latest", workflow)
|
|
self.assertIn("type=gha,scope=desktop", workflow)
|
|
self.assertIn("type=gha,scope=runtime", workflow)
|
|
self.assertIn("desktop-latest", workflow)
|
|
|
|
def test_desktop_job_uses_image_without_live_bootstrap_downloads(self) -> None:
|
|
workflow = E2E_WORKFLOW.read_text(encoding="utf-8")
|
|
desktop_job = job_block(workflow, "desktop-e2e", "e2e-report")
|
|
|
|
self.assertIn("image: ghcr.io/kdlbs/kandev-ci:desktop-latest", desktop_job)
|
|
self.assertIn("options: --ipc=host", desktop_job)
|
|
self.assertIn("git config --global --add safe.directory", desktop_job)
|
|
self.assertIn("path: ~/.local/share/pnpm/store", desktop_job)
|
|
self.assertIn("pnpm install --frozen-lockfile", desktop_job)
|
|
self.assertIn("pnpm --filter @kandev/desktop e2e", desktop_job)
|
|
|
|
for forbidden in (
|
|
"pnpm/action-setup",
|
|
"actions/setup-node",
|
|
"rustup toolchain install",
|
|
"apt-get",
|
|
"sudo",
|
|
):
|
|
self.assertNotIn(forbidden, desktop_job)
|
|
|
|
changes_job = job_block(workflow, "changes", "build")
|
|
for pattern in (
|
|
".github/docker/ci-base/**",
|
|
".github/workflows/ci-base-image.yml",
|
|
):
|
|
self.assertIn(pattern, changes_job)
|
|
|
|
def test_contract_runs_in_the_unfiltered_required_workflow(self) -> None:
|
|
workflow = LINT_WORKFLOW.read_text(encoding="utf-8")
|
|
|
|
self.assertIn(
|
|
"python3 .github/scripts/e2e-tests-workflow-contract_test.py",
|
|
workflow,
|
|
)
|
|
for trigger in ("push", "pull_request", "merge_group"):
|
|
trigger_marker = f" {trigger}:"
|
|
_, separator, trigger_block_text = workflow.partition(trigger_marker)
|
|
self.assertTrue(separator, f"Lint workflow has no {trigger} trigger")
|
|
self.assertNotIn(" paths:", trigger_block_text.split("\n ", 1)[0])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|