utils/scripts/tests/test_dep_freshness_changed.py

115 lines
3.6 KiB
Python

"""dep_freshness_changed.sh: the pre-commit hook only gates manifests this branch changed.
Each test builds a throwaway git repo with a `main` branch and points the
wrapper at a stub gate (DEP_FRESHNESS_GATE) that records its arguments, so
nothing touches the network and the only thing under test is the filtering.
"""
from __future__ import annotations
import os
import subprocess
from pathlib import Path
import pytest
SCRIPT = Path(__file__).resolve().parent.parent / "dep_freshness_changed.sh"
STUB = """\
#!/bin/bash
printf '%s\\n' "$@" > "$STUB_LOG"
exit "${STUB_EXIT:-0}"
"""
def _git(repo: Path, *args: str) -> None:
subprocess.run(["git", *args], cwd=repo, check=True, capture_output=True)
@pytest.fixture
def repo(tmp_path: Path) -> Path:
"""Repo on `main` with two committed manifests, then a feature branch."""
root = tmp_path / "repo"
root.mkdir()
_git(root, "init", "-q", "-b", "main")
_git(root, "config", "user.email", "t@example.invalid")
_git(root, "config", "user.name", "t")
for sub in ("touched", "untouched"):
(root / sub).mkdir()
(root / sub / "requirements.txt").write_text("ruff==0.1.0\n")
_git(root, "add", ".")
_git(root, "commit", "-q", "-m", "init")
_git(root, "checkout", "-q", "-b", "feature")
return root
def _run(
repo: Path, tmp_path: Path, *files: str, **env: str
) -> tuple[int, list[str] | None]:
stub = tmp_path / "stub.sh"
stub.write_text(STUB)
stub.chmod(0o755)
log = tmp_path / "stub.log"
log.unlink(missing_ok=True)
full_env = {
**os.environ,
"DEP_FRESHNESS_GATE": str(stub),
"STUB_LOG": str(log),
**env,
}
proc = subprocess.run(
["bash", str(SCRIPT), *files],
check=False,
cwd=repo,
env=full_env,
capture_output=True,
text=True,
)
forwarded = log.read_text().split() if log.exists() else None
return proc.returncode, forwarded
ALL = ("touched/requirements.txt", "untouched/requirements.txt")
def test_forwards_only_uncommitted_change(repo: Path, tmp_path: Path) -> None:
(repo / "touched" / "requirements.txt").write_text("ruff==0.2.0\n")
assert _run(repo, tmp_path, *ALL) == (0, ["touched/requirements.txt"])
def test_forwards_committed_branch_change(repo: Path, tmp_path: Path) -> None:
(repo / "touched" / "requirements.txt").write_text("ruff==0.2.0\n")
_git(repo, "commit", "-q", "-am", "bump")
assert _run(repo, tmp_path, *ALL) == (0, ["touched/requirements.txt"])
def test_forwards_untracked_manifest(repo: Path, tmp_path: Path) -> None:
(repo / "new").mkdir()
(repo / "new" / "requirements.txt").write_text("ruff==0.1.0\n")
assert _run(repo, tmp_path, *ALL, "new/requirements.txt") == (
0,
["new/requirements.txt"],
)
def test_no_branch_change_skips_gate(repo: Path, tmp_path: Path) -> None:
assert _run(repo, tmp_path, *ALL) == (0, None)
def test_gate_failure_propagates(repo: Path, tmp_path: Path) -> None:
(repo / "touched" / "requirements.txt").write_text("ruff==0.2.0\n")
assert _run(repo, tmp_path, *ALL, STUB_EXIT="1") == (
1,
["touched/requirements.txt"],
)
def test_unresolvable_base_fails_closed(repo: Path, tmp_path: Path) -> None:
code, forwarded = _run(repo, tmp_path, *ALL, DEP_FRESHNESS_BASE="no-such-ref")
assert (code, forwarded) == (0, list(ALL))
def test_subdirectory_cwd_fails_closed(repo: Path, tmp_path: Path) -> None:
code, forwarded = _run(repo / "touched", tmp_path, "requirements.txt")
assert (code, forwarded) == (0, ["requirements.txt"])