"""Tests for smoke workflow CI configuration. Validates that the GitHub Actions / Gitea Actions smoke workflow actually runs the standalone CMake build and test suite, not just parse checks. """ from pathlib import Path import yaml import pytest WORKFLOW_PATH = Path(".gitea/workflows/smoke.yml") @pytest.fixture def workflow(): """Load and parse the smoke workflow YAML.""" content = WORKFLOW_PATH.read_text(encoding="utf-8") return yaml.safe_load(content) def test_smoke_workflow_exists(): """Smoke workflow file must exist.""" assert WORKFLOW_PATH.exists(), f"Missing {WORKFLOW_PATH}" def test_smoke_has_cmake_configure_step(workflow): """Smoke workflow must configure the CMake project with tests enabled.""" steps = workflow["jobs"]["smoke"]["steps"] cmake_found = False for step in steps: run = step.get("run", "") if "cmake -S . -B build" in run and "TURBOQUANT_BUILD_TESTS=ON" in run: cmake_found = True break assert cmake_found, ( "Smoke workflow missing cmake configure step with TURBOQUANT_BUILD_TESTS=ON" ) def test_smoke_has_cmake_build_step(workflow): """Smoke workflow must build the CMake project.""" steps = workflow["jobs"]["smoke"]["steps"] build_found = False for step in steps: run = step.get("run", "") if "cmake --build build" in run: build_found = True break assert build_found, "Smoke workflow missing cmake --build step" def test_smoke_has_ctest_step(workflow): """Smoke workflow must run ctest.""" steps = workflow["jobs"]["smoke"]["steps"] ctest_found = False for step in steps: run = step.get("run", "") if "ctest" in run and "output-on-failure" in run: ctest_found = True break assert ctest_found, "Smoke workflow missing ctest --output-on-failure step" def test_smoke_build_before_secret_scan(workflow): """Build and test steps must run before secret scan (fail fast on build errors).""" steps = workflow["jobs"]["smoke"]["steps"] names = [s.get("name", "") for s in steps] build_idx = None scan_idx = None for i, name in enumerate(names): if "cmake" in name.lower() or "build" in name.lower(): if build_idx is None: build_idx = i if "secret" in name.lower(): scan_idx = i if build_idx is not None and scan_idx is not None: assert build_idx < scan_idx, ( "Build step should run before secret scan to fail fast on broken code" )