"""ORCH-073 — conditionality / backward-compat (INV-5). Covers TC-17/18 / AC-6. The whole under-gate and the regression guard are no-ops for non-self repos and when their kill-switches are off, so enduro-trails and a disabled self-host behave exactly as before. """ import os import tempfile os.environ.setdefault("ORCH_GITEA_TOKEN", "test-token") os.environ.setdefault("ORCH_PLANE_API_TOKEN", "test-token") os.environ.setdefault("ORCH_DB_PATH", os.path.join(tempfile.gettempdir(), "test_orch073_cond.db")) from unittest.mock import MagicMock # noqa: E402 from src import merge_gate, stage_engine, image_freshness # noqa: E402 from src.stage_engine import AdvanceResult, _handle_merge_verify # noqa: E402 REPO = "orchestrator" WI = "ORCH-073" BRANCH = "feature/ORCH-073-x" # --------------------------------------------------------------------------- # TC-17 (AC-6/INV-5): non-self repo / kill-switch off -> under-gate is a no-op. # --------------------------------------------------------------------------- def test_tc17_merge_verify_applies_scope(monkeypatch): monkeypatch.setattr(merge_gate.settings, "merge_verify_enabled", True) monkeypatch.setattr(merge_gate.settings, "merge_verify_repos", "") # Empty CSV -> only the self-hosting repo. assert merge_gate.merge_verify_applies("orchestrator") is True assert merge_gate.merge_verify_applies("enduro-trails") is False # Kill-switch off -> no-op for everyone. monkeypatch.setattr(merge_gate.settings, "merge_verify_enabled", False) assert merge_gate.merge_verify_applies("orchestrator") is False def test_tc17_under_gate_noop_for_non_self(monkeypatch): # When the under-gate does not apply, _handle_merge_verify advances (False) and # never touches the merge-actor / verifier / guard. monkeypatch.setattr(stage_engine.merge_gate, "merge_verify_applies", lambda r: False) def must_not_call(*a, **k): raise AssertionError("under-gate must be a no-op for non-self repos") monkeypatch.setattr(stage_engine.merge_gate, "merge_pr", must_not_call) monkeypatch.setattr(stage_engine.merge_gate, "verify_merged_to_main", must_not_call) monkeypatch.setattr(stage_engine.merge_gate, "check_main_regression", must_not_call) res = AdvanceResult() assert _handle_merge_verify(1, "enduro-trails", WI, BRANCH, res) is False assert res.alerted is False # --------------------------------------------------------------------------- # TC-18 (INV-5): regression guard respects its kill-switch -> no-op; SHA-in-main # alone still advances the task. # --------------------------------------------------------------------------- def test_tc18_guard_kill_switch_skips_guard(monkeypatch): monkeypatch.setattr(stage_engine.merge_gate, "merge_verify_applies", lambda r: True) monkeypatch.setattr(stage_engine.settings, "regression_guard_enabled", False) monkeypatch.setattr(image_freshness, "validated_revision", lambda r, b: "deadbeef") monkeypatch.setattr(stage_engine.merge_gate, "merge_pr", lambda r, b: (True, "merged PR #1")) monkeypatch.setattr(stage_engine.merge_gate, "verify_merged_to_main", lambda r, b, s: True) monkeypatch.setattr( stage_engine.merge_gate, "check_main_regression", lambda r, b: (_ for _ in ()).throw(AssertionError("guard must not run when disabled")), ) monkeypatch.setattr( stage_engine.self_deploy, "record_merged_to_main", MagicMock(return_value=True) ) for name in ("set_issue_blocked", "plane_add_comment", "send_telegram", "link_for"): monkeypatch.setattr(stage_engine, name, MagicMock()) res = AdvanceResult() # Guard disabled -> confirmed SHA-in-main advances straight to done (return False). assert _handle_merge_verify(1, REPO, WI, BRANCH, res) is False assert res.alerted is False assert not stage_engine.set_issue_blocked.called def test_tc18_guard_noop_for_non_self_repo(monkeypatch): # check_main_regression is only invoked inside the confirmed branch which itself # only runs when merge_verify_applies is True (self-hosting / CSV). For a non-self # repo the guard is never reached. monkeypatch.setattr(stage_engine.merge_gate, "merge_verify_applies", lambda r: False) monkeypatch.setattr( stage_engine.merge_gate, "check_main_regression", lambda r, b: (_ for _ in ()).throw(AssertionError("guard must not run for non-self")), ) res = AdvanceResult() assert _handle_merge_verify(1, "enduro-trails", WI, BRANCH, res) is False