feat(harness): P4 — custom-test ergonomics (rcust)
All checks were successful
continuous-integration/drone/push Build is passing

Placement RULE: discovery.custom_tests covers ONLY functional/ + playwright/ —
the top-level test_*.py glob for recipe dirs is removed (top level is reserved
for lifecycle overlays; zero in-repo users of top-level custom tests, verified
by sweep). Lifecycle-name exclusion inside the subdirs stays as the double-run
safety net. HC2 default-deny unchanged (repo-local custom now pinned via
functional/ in the gate test).

New conftest fixture op_state: parses $CCCI_OP_STATE_FILE (op context: versions,
artifact paths), skipping with a clear reason when unset/absent/unparseable —
overlay tests read op facts from the fixture instead of hand-parsing env (zero
existing hand-parsers found; the fixture is the documented path forward). deps
fixture landed in P2d.

Unit tests: placement-rule discovery tests (top-level custom NOT discovered;
functional/playwright are; misfiled lifecycle names excluded), op_state fixture
contract (reads file / skips without env / skips on missing file), deps fixture
attribute sugar.

Verified on cc-ci: cc-ci-run -m pytest tests/unit -q -> 184 passed; scripts/lint.sh -> PASS.
This commit is contained in:
autonomic-bot
2026-06-10 17:14:21 +00:00
parent fd02d9f4b8
commit 29a28e2028
5 changed files with 95 additions and 30 deletions

View File

@ -1,6 +1,6 @@
"""Unit tests for Phase-2 discovery additions (plan §4.1).
Proves the `custom_tests` discovery recurses into the per-recipe `functional/` + `playwright/`
Proves the `custom_tests` discovery covers exactly the per-recipe `functional/` + `playwright/`
subdirs as well as the top-level dir, while still excluding lifecycle `test_<op>.py` names and
honouring the HC2 repo-local approval gate.
@ -27,16 +27,16 @@ def teardown_function():
os.environ.pop("CCCI_REPO_LOCAL_APPROVED_FILE", None)
def test_custom_tests_recurses_functional_and_playwright(tmp_path, monkeypatch):
"""A Phase-2 cc-ci recipe layout: functional/test_*.py + playwright/test_*.py + top-level
test_*.py — all are discovered as custom tests; the lifecycle names are excluded."""
def test_custom_tests_placement_rule_functional_playwright_only(tmp_path, monkeypatch):
"""Placement rule (rcust P4): custom tests are discovered ONLY under functional/ +
playwright/. A top-level non-lifecycle test_*.py is NOT discovered (top level is reserved
for lifecycle overlays); lifecycle names inside the subdirs stay excluded (defensive)."""
# Point cc-ci's per-recipe dir at a fake recipe in tmp_path
fake_recipe = "ccci-phase2-fixture"
fake_dir = tmp_path / "tests" / fake_recipe
(fake_dir / "functional").mkdir(parents=True)
(fake_dir / "playwright").mkdir()
# legitimate custom tests at multiple levels
(fake_dir / "test_sso_smoke.py").write_text("# top-level cross-cutting\n")
(fake_dir / "test_sso_smoke.py").write_text("# top-level — NOT discovered since P4\n")
(fake_dir / "functional" / "test_health_check.py").write_text("# parity port\n")
(fake_dir / "functional" / "test_content_roundtrip.py").write_text("# recipe-specific\n")
(fake_dir / "playwright" / "test_login_flow.py").write_text("# UI flow\n")
@ -49,11 +49,11 @@ def test_custom_tests_recurses_functional_and_playwright(tmp_path, monkeypatch):
customs = discovery.custom_tests(fake_recipe, None)
names = sorted((src, os.path.basename(p)) for src, p in customs)
# Top-level + functional/ + playwright/ all discovered; lifecycle name excluded
assert ("cc-ci", "test_sso_smoke.py") in names
# functional/ + playwright/ discovered; top-level custom + lifecycle name are NOT
assert ("cc-ci", "test_health_check.py") in names
assert ("cc-ci", "test_content_roundtrip.py") in names
assert ("cc-ci", "test_login_flow.py") in names
assert ("cc-ci", "test_sso_smoke.py") not in names
assert ("cc-ci", "test_install.py") not in names