feat(harness): P4 — custom-test ergonomics (rcust)
All checks were successful
continuous-integration/drone/push Build is passing
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:
@ -40,6 +40,28 @@ def live_app() -> str:
|
||||
return domain
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def op_state() -> dict:
|
||||
"""The orchestrator's run-scoped op context (rcust P4): versions, artifact paths — written to
|
||||
`$CCCI_OP_STATE_FILE` after each lifecycle op (e.g. `{"upgrade": {"before": {...},
|
||||
"head_ref": ...}, "backup": {"snapshot_id": ...}}`). Overlay tests read op facts from here
|
||||
instead of hand-parsing env/JSON. Skips with a clear reason outside an orchestrator run."""
|
||||
import json
|
||||
|
||||
path = os.environ.get("CCCI_OP_STATE_FILE")
|
||||
if not path:
|
||||
pytest.skip(
|
||||
"CCCI_OP_STATE_FILE not set — op_state is only available under the orchestrator"
|
||||
)
|
||||
if not os.path.exists(path):
|
||||
pytest.skip(f"op-state file missing ({path}) — orchestrator has not performed an op yet")
|
||||
try:
|
||||
with open(path) as f:
|
||||
return json.load(f)
|
||||
except ValueError:
|
||||
pytest.skip(f"op-state file unreadable/not JSON ({path})")
|
||||
|
||||
|
||||
class _DepEntry(dict):
|
||||
"""One provisioned dep (full creds dict) with attribute sugar: `entry.domain`, `entry.realm`,
|
||||
`entry.client_secret`, ... — dict-style access works too (rcust P2d)."""
|
||||
|
||||
Reference in New Issue
Block a user