"""ORCH-059 TC-01/02/03: resolver registration of the dedicated "Confirm Deploy" status and its fail-closed absence in fallback environments. Contract (AC-1, AC-7): * TC-01 — _PLANE_NAME_TO_KEY maps the board name "Confirm Deploy" to the logical key "confirm_deploy". * TC-02 — get_project_states for an ORCH-like project (Plane API mocked to include a "Confirm Deploy" state) returns a NON-empty uuid under "confirm_deploy", distinct from "approved". * TC-03 — fail-closed: when the status is absent (API fallback to _DEFAULT_STATES / unreachable Plane), the key is simply missing and a .get access yields None WITHOUT raising — the confirm-deploy branch never activates. """ import os import tempfile import pytest os.environ.setdefault("ORCH_PLANE_API_TOKEN", "test-token") os.environ.setdefault("ORCH_GITEA_TOKEN", "test-token") os.environ["ORCH_DB_PATH"] = os.path.join(tempfile.gettempdir(), "test_orch_plane_states.db") import src.plane_sync as plane_sync # noqa: E402 from src.plane_sync import ( # noqa: E402 _PLANE_NAME_TO_KEY, _DEFAULT_STATES, get_project_states, reload_project_states, ) @pytest.fixture(autouse=True) def fresh_cache(): reload_project_states() yield reload_project_states() # --------------------------------------------------------------------------- # TC-01: name -> key mapping is registered # --------------------------------------------------------------------------- def test_tc01_confirm_deploy_name_to_key_mapping(): assert _PLANE_NAME_TO_KEY.get("Confirm Deploy") == "confirm_deploy" def test_tc01_confirm_deploy_not_in_default_states(): """Fail-closed by construction: NO fallback UUID exists for confirm_deploy, so enduro / API-fallback environments never resolve a (wrong) deploy trigger.""" assert "confirm_deploy" not in _DEFAULT_STATES # --------------------------------------------------------------------------- # TC-02: live API resolves a real, distinct uuid for an ORCH-like project # --------------------------------------------------------------------------- def test_tc02_get_project_states_resolves_confirm_deploy(monkeypatch): confirm_uuid = "cfd00000-0000-0000-0000-000000000059" approved_uuid = "a519a341-dada-4a91-8910-7604f82b79c5" class _Resp: def raise_for_status(self): pass def json(self): return { "results": [ {"name": "In Progress", "id": "b873d9eb-993c-48cd-97ac-99a9b1623967"}, {"name": "Approved", "id": approved_uuid}, {"name": "Confirm Deploy", "id": confirm_uuid}, ] } monkeypatch.setattr(plane_sync.httpx, "get", lambda *a, **k: _Resp()) states = get_project_states("orch-project-uuid") assert states.get("confirm_deploy") == confirm_uuid # Distinct gestures: confirm-deploy must NOT alias the human "Approved" gate. assert states["confirm_deploy"] != states["approved"] # --------------------------------------------------------------------------- # TC-03: fail-closed when the status is absent (API fallback / unreachable) # --------------------------------------------------------------------------- def test_tc03_fail_closed_when_api_unreachable(monkeypatch): """A Plane outage -> get_project_states falls back to _DEFAULT_STATES, which has no confirm_deploy key. .get must yield None, never raise.""" def _boom(*a, **k): raise RuntimeError("plane down") monkeypatch.setattr(plane_sync.httpx, "get", _boom) states = get_project_states("any-project-uuid") # No KeyError, branch never activates. assert states.get("confirm_deploy") is None # The human gate "Approved" still resolves (fallback is intact). assert states.get("approved") == _DEFAULT_STATES["approved"] def test_tc03_fail_closed_when_status_not_on_board(monkeypatch): """Project whose board lacks "Confirm Deploy": the key is filled by NEITHER the API loop NOR the _DEFAULT_STATES backfill -> absent -> fail-closed.""" class _Resp: def raise_for_status(self): pass def json(self): return { "results": [ {"name": "In Progress", "id": "b873d9eb-993c-48cd-97ac-99a9b1623967"}, {"name": "Approved", "id": "a519a341-dada-4a91-8910-7604f82b79c5"}, ] } monkeypatch.setattr(plane_sync.httpx, "get", lambda *a, **k: _Resp()) states = get_project_states("board-without-confirm") assert states.get("confirm_deploy") is None assert states.get("approved") == "a519a341-dada-4a91-8910-7604f82b79c5"