test_close_ritual_land_check.py
python
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
1 day ago
| 1 | """Unit tests for close_ritual land-check.""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | import subprocess |
| 6 | import tempfile |
| 7 | import unittest |
| 8 | from pathlib import Path |
| 9 | |
| 10 | from adapters.config import load_config |
| 11 | from tools.close_ritual.land_check import run_land_check |
| 12 | |
| 13 | |
| 14 | def _minimal_config_yaml(tmp_path: Path, *, close_ritual: str) -> Path: |
| 15 | cfg = tmp_path / ".overseer" / "config.yaml" |
| 16 | cfg.parent.mkdir(parents=True) |
| 17 | cfg.write_text( |
| 18 | f""" |
| 19 | overseer_config_version: 1 |
| 20 | repo: |
| 21 | name: fixture |
| 22 | root_relative_docs: "." |
| 23 | vcs: |
| 24 | regime: git-only |
| 25 | canonical: git |
| 26 | git: |
| 27 | remote: origin |
| 28 | main_branch: main |
| 29 | mirror_branch: null |
| 30 | feature_branch_pattern: "feat/{{slug}}" |
| 31 | muse: |
| 32 | staging_remote: null |
| 33 | main_branch: null |
| 34 | working_dir: null |
| 35 | docs: |
| 36 | handover: OVERSEER_HANDOVER.md |
| 37 | roadmap: ROADMAP.md |
| 38 | standing_decisions: ROADMAP.md |
| 39 | thresholds: |
| 40 | realign_max_commits: 50 |
| 41 | drift_warn_only: true |
| 42 | freeze_contract: |
| 43 | enabled: true |
| 44 | reviewer: |
| 45 | mode: agent |
| 46 | model: thinking-high |
| 47 | provider: local |
| 48 | fallback: human |
| 49 | human_escalation: [security] |
| 50 | {close_ritual} |
| 51 | """, |
| 52 | encoding="utf-8", |
| 53 | ) |
| 54 | return cfg |
| 55 | |
| 56 | |
| 57 | class CloseRitualLandCheckTests(unittest.TestCase): |
| 58 | def test_close_ritual_disabled_noop(self) -> None: |
| 59 | with tempfile.TemporaryDirectory() as tmp: |
| 60 | tmp_path = Path(tmp) |
| 61 | cfg_path = _minimal_config_yaml( |
| 62 | tmp_path, |
| 63 | close_ritual="close_ritual:\n enabled: false\n require_paths: []\n", |
| 64 | ) |
| 65 | config = load_config(cfg_path) |
| 66 | result = run_land_check(config, tmp_path) |
| 67 | self.assertEqual(result.exit_code, 0) |
| 68 | self.assertFalse(result.auto_merge) |
| 69 | |
| 70 | def test_verify_landed_pass_when_matching(self) -> None: |
| 71 | with tempfile.TemporaryDirectory() as tmp: |
| 72 | tmp_path = Path(tmp) |
| 73 | init = subprocess.run( |
| 74 | ["git", "init", "-b", "main"], cwd=tmp_path, capture_output=True, text=True |
| 75 | ) |
| 76 | if init.returncode != 0: |
| 77 | self.skipTest(f"git init unavailable: {init.stderr}") |
| 78 | subprocess.run( |
| 79 | ["git", "config", "user.email", "[email protected]"], |
| 80 | cwd=tmp_path, |
| 81 | check=True, |
| 82 | capture_output=True, |
| 83 | ) |
| 84 | subprocess.run( |
| 85 | ["git", "config", "user.name", "t"], |
| 86 | cwd=tmp_path, |
| 87 | check=True, |
| 88 | capture_output=True, |
| 89 | ) |
| 90 | doc = tmp_path / "BOARD.json" |
| 91 | doc.write_text('{"ok": true}\n', encoding="utf-8") |
| 92 | subprocess.run(["git", "add", "-A"], cwd=tmp_path, check=True, capture_output=True) |
| 93 | subprocess.run( |
| 94 | ["git", "commit", "-m", "init"], |
| 95 | cwd=tmp_path, |
| 96 | check=True, |
| 97 | capture_output=True, |
| 98 | ) |
| 99 | |
| 100 | cfg_path = _minimal_config_yaml( |
| 101 | tmp_path, |
| 102 | close_ritual=( |
| 103 | "close_ritual:\n" |
| 104 | " enabled: true\n" |
| 105 | " mode: verify_landed\n" |
| 106 | " require_paths:\n" |
| 107 | " - BOARD.json\n" |
| 108 | ), |
| 109 | ) |
| 110 | config = load_config(cfg_path) |
| 111 | from unittest.mock import patch |
| 112 | |
| 113 | from tools.governance_freshness import GovernanceFreshnessReport |
| 114 | |
| 115 | ok_fresh = GovernanceFreshnessReport( |
| 116 | state="not_applicable", message="patched", remediation=None |
| 117 | ) |
| 118 | with patch( |
| 119 | "tools.close_ritual.land_check.check_governance_freshness", |
| 120 | return_value=ok_fresh, |
| 121 | ): |
| 122 | result = run_land_check(config, tmp_path) |
| 123 | self.assertEqual(result.exit_code, 0, msg=result.messages) |
| 124 | self.assertTrue(result.landed) |
| 125 | self.assertFalse(result.auto_merge) |
| 126 | |
| 127 | def test_verify_landed_fail_on_mismatch(self) -> None: |
| 128 | with tempfile.TemporaryDirectory() as tmp: |
| 129 | tmp_path = Path(tmp) |
| 130 | init = subprocess.run( |
| 131 | ["git", "init", "-b", "main"], cwd=tmp_path, capture_output=True, text=True |
| 132 | ) |
| 133 | if init.returncode != 0: |
| 134 | self.skipTest(f"git init unavailable: {init.stderr}") |
| 135 | subprocess.run( |
| 136 | ["git", "config", "user.email", "[email protected]"], |
| 137 | cwd=tmp_path, |
| 138 | check=True, |
| 139 | capture_output=True, |
| 140 | ) |
| 141 | subprocess.run( |
| 142 | ["git", "config", "user.name", "t"], |
| 143 | cwd=tmp_path, |
| 144 | check=True, |
| 145 | capture_output=True, |
| 146 | ) |
| 147 | doc = tmp_path / "BOARD.json" |
| 148 | doc.write_text('{"ok": true}\n', encoding="utf-8") |
| 149 | subprocess.run(["git", "add", "-A"], cwd=tmp_path, check=True, capture_output=True) |
| 150 | subprocess.run( |
| 151 | ["git", "commit", "-m", "init"], |
| 152 | cwd=tmp_path, |
| 153 | check=True, |
| 154 | capture_output=True, |
| 155 | ) |
| 156 | doc.write_text('{"ok": false}\n', encoding="utf-8") |
| 157 | |
| 158 | cfg_path = _minimal_config_yaml( |
| 159 | tmp_path, |
| 160 | close_ritual=( |
| 161 | "close_ritual:\n" |
| 162 | " enabled: true\n" |
| 163 | " mode: verify_landed\n" |
| 164 | " require_paths:\n" |
| 165 | " - BOARD.json\n" |
| 166 | ), |
| 167 | ) |
| 168 | config = load_config(cfg_path) |
| 169 | result = run_land_check(config, tmp_path) |
| 170 | self.assertEqual(result.exit_code, 1) |
| 171 | self.assertFalse(result.landed) |
| 172 | |
| 173 | |
| 174 | if __name__ == "__main__": |
| 175 | unittest.main() |
File History
1 commit
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
1 day ago