Files
cc-ci/tests/unit/test_deps.py
autonomic-bot 9a7772563a style: repo-wide lint pass — make the lint gate green again
Push builds have been RED on the lint step since ~build 209 from accumulated
formatting drift. This is the mechanical cleanup: ruff format + ruff --fix
(UP038 isinstance unions, SIM105 contextlib.suppress, UP031 f-strings, SIM115
tempfile context manager), shfmt -i 2 -ci, nixpkgs-fmt/statix/deadnix (merged
attrsets, dropped unused lib args), yamllint, and shell quoting fixes in
tests/lasuite-docs/setup_custom_tests.sh. No behaviour changes intended;
lint: PASS, unit tests: 138 passed.
2026-06-09 21:56:15 +00:00

101 lines
4.3 KiB
Python

"""Unit tests for runner/harness/deps.py (Phase 2 §4.2 / Q2.3).
Pure-Python: no real deploys. Tests the declarative parts of the dep resolver — declared_deps
reading from `tests/<recipe>/recipe_meta.py`, the per-dep domain derivation, and write/load of the
run state file. The deploy_deps + teardown_deps integration is exercised by real e2e against cc-ci
(Q2.4 acceptance).
"""
from __future__ import annotations
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "runner"))
from harness import deps # noqa: E402
def test_declared_deps_returns_empty_for_no_meta(monkeypatch, tmp_path):
"""A recipe with no recipe_meta.py returns []."""
fake_recipe = "ccci-no-meta"
# No file at tests/<fake_recipe>/recipe_meta.py -> declared_deps reads nothing -> []
monkeypatch.chdir(tmp_path)
assert deps.declared_deps(fake_recipe) == []
def test_declared_deps_reads_DEPS_list(tmp_path, monkeypatch):
"""A recipe_meta.py with `DEPS = [...]` returns the list."""
fake_recipe = "ccci-with-deps"
# Build a fake repo layout under tmp_path
recipe_dir = tmp_path / "tests" / fake_recipe
recipe_dir.mkdir(parents=True)
(recipe_dir / "recipe_meta.py").write_text('HEALTH_PATH = "/"\nDEPS = ["keycloak", "redis"]\n')
# Patch the deps module's idea of "where the repo is" by monkey-patching __file__ for the
# function indirectly: declared_deps uses `os.path.dirname(__file__), "..", "..", "tests"` —
# which resolves to the real repo's `tests/`. So instead, override that with a symlink/dir
# under tmp_path: deps.__file__ points at the runner module. We can't easily relocate that.
# Instead, mock the path by writing the fake recipe under the REAL tests/ dir.
real_tests = os.path.join(os.path.dirname(deps.__file__), "..", "..", "tests")
target_dir = os.path.join(real_tests, fake_recipe)
os.makedirs(target_dir, exist_ok=True)
target_meta = os.path.join(target_dir, "recipe_meta.py")
try:
with open(target_meta, "w") as f:
f.write('DEPS = ["keycloak", "redis"]\n')
result = deps.declared_deps(fake_recipe)
assert result == ["keycloak", "redis"]
finally:
if os.path.exists(target_meta):
os.remove(target_meta)
if os.path.isdir(target_dir):
os.rmdir(target_dir)
def test_dep_domain_distinct_per_dep():
"""Two deps of different kinds (same parent/pr/ref) get distinct per-run domains."""
parent = "lasuite-docs"
pr = "42"
ref = "abc123"
d1 = deps.dep_domain(parent, pr, ref, "keycloak")
d2 = deps.dep_domain(parent, pr, ref, "redis")
assert d1 != d2
# Both must look like the standard run-app pattern: <recipe[:4]>-<6hex>.ci.commoninternet.net
assert d1.endswith(".ci.commoninternet.net")
assert d2.endswith(".ci.commoninternet.net")
# The hash is determined by (parent, pr, ref, dep) — same inputs = same domain (idempotent)
assert deps.dep_domain(parent, pr, ref, "keycloak") == d1
def test_dep_domain_distinct_per_parent():
"""The same dep deployed by two different parent recipes (same dep, pr, ref) gets distinct
domains — proves the dep is parent-scoped not just dep-name-scoped."""
d1 = deps.dep_domain("lasuite-docs", "42", "abc", "keycloak")
d2 = deps.dep_domain("cryptpad", "42", "abc", "keycloak")
assert d1 != d2
def test_write_and_load_run_state(tmp_path, monkeypatch):
"""write_run_state writes JSON to $CCCI_DEPS_FILE; load_run_state reads it back."""
state_path = tmp_path / "deps.json"
monkeypatch.setenv("CCCI_DEPS_FILE", str(state_path))
state = [
{"recipe": "keycloak", "domain": "kc-deadbe.ci.commoninternet.net"},
{"recipe": "redis", "domain": "redi-abc123.ci.commoninternet.net"},
]
deps.write_run_state(state)
loaded = deps.load_run_state()
assert loaded == state
def test_load_run_state_missing_env_returns_empty(monkeypatch):
"""No $CCCI_DEPS_FILE -> empty list."""
monkeypatch.delenv("CCCI_DEPS_FILE", raising=False)
assert deps.load_run_state() == []
def test_write_run_state_no_env_is_noop(monkeypatch):
"""write_run_state silently no-ops without $CCCI_DEPS_FILE (so standalone helper use doesn't
require setting up the env)."""
monkeypatch.delenv("CCCI_DEPS_FILE", raising=False)
deps.write_run_state([{"recipe": "x", "domain": "y"}]) # must not raise