test_upgrade_regime_unit.py python
170 lines 5.5 KB
Raw
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 2 days ago
1 """Unit tests — Track O / O3 upgrade-regime classifiers and gates (§O2.9 unit)."""
2
3 from __future__ import annotations
4
5 from pathlib import Path
6
7 from adapters.config import load_config
8 from adapters.runner import CommandResult
9 from adapters.templating import render_template
10 from cli.config_gen import load_config_from_dict
11 from cli.kit_root import kit_root
12 from cli.main import build_parser
13 from tests.support import FIXTURES, make_runner, ok, write_config
14 from tools.upgrade_regime.ceremony import (
15 StartState,
16 build_upgraded_config_dict,
17 check_g3_deploy_script,
18 check_g4_deploy_script,
19 check_g5_deploy_script,
20 check_g6_deploy_script,
21 check_g8_git_remote,
22 classify_start_state,
23 docs_preserved,
24 is_silent_regime_only_patch,
25 required_vcs_complete,
26 )
27
28
29 def _load_muse_only():
30 return load_config(FIXTURES / "config-muse-only.yaml")
31
32
33 def test_argparse_frozen_flags() -> None:
34 parser = build_parser()
35 args = parser.parse_args(
36 [
37 "upgrade-regime",
38 "--from",
39 "muse-only",
40 "--to",
41 "muse+git-mirror",
42 "--dry-run",
43 "--apply",
44 "--live-bridge",
45 "--force",
46 "-y",
47 ]
48 )
49 assert args.command == "upgrade-regime"
50 assert args.from_regime == "muse-only"
51 assert args.to_regime == "muse+git-mirror"
52 assert args.dry_run is True
53 assert args.apply is True
54 assert args.live_bridge is True
55 assert args.force is True
56 assert args.yes is True
57
58
59 def test_argparse_rejects_unsupported_from_pair() -> None:
60 parser = build_parser()
61 try:
62 parser.parse_args(["upgrade-regime", "--from", "git-only", "--to", "muse+git-mirror"])
63 raise AssertionError("expected SystemExit")
64 except SystemExit as exc:
65 assert exc.code == 2
66
67
68 def test_classify_muse_only(tmp_path: Path) -> None:
69 write_config(tmp_path, "config-muse-only.yaml")
70 state = classify_start_state(tmp_path, tmp_path / ".overseer" / "config.yaml")
71 assert state == StartState.MUSE_ONLY
72
73
74 def test_classify_missing_config(tmp_path: Path) -> None:
75 state = classify_start_state(tmp_path, tmp_path / ".overseer" / "config.yaml")
76 assert state == StartState.MISSING_CONFIG
77
78
79 def test_classify_wrong_regime_git_only(tmp_path: Path) -> None:
80 write_config(tmp_path, "config-git-only.yaml")
81 state = classify_start_state(tmp_path, tmp_path / ".overseer" / "config.yaml")
82 assert state == StartState.WRONG_REGIME
83
84
85 def test_classify_incomplete_upgrade_without_bridge(tmp_path: Path) -> None:
86 write_config(tmp_path, "config-muse-git-mirror.yaml")
87 state = classify_start_state(tmp_path, tmp_path / ".overseer" / "config.yaml")
88 assert state == StartState.INCOMPLETE_UPGRADE
89
90
91 def test_classify_complete_upgrade(tmp_path: Path) -> None:
92 from tests.support import muse_mirror_status_runner, run_cli, seed_muse_substrate
93 from cli.kit_root import kit_root
94
95 seed_muse_substrate(tmp_path)
96 assert (
97 run_cli(
98 [
99 "init",
100 "--from-config",
101 str(FIXTURES / "config-muse-git-mirror.yaml"),
102 "--non-interactive",
103 ],
104 cwd=tmp_path,
105 kit=kit_root(),
106 runner=muse_mirror_status_runner(tmp_path),
107 )
108 == 0
109 )
110 state = classify_start_state(tmp_path, tmp_path / ".overseer" / "config.yaml")
111 assert state == StartState.COMPLETE_UPGRADE
112
113
114 def test_required_vcs_complete_and_build_preserves_docs() -> None:
115 before = _load_muse_only()
116 assert not required_vcs_complete(before)
117 data = build_upgraded_config_dict(before)
118 after = load_config_from_dict(data, "proj.yaml")
119 assert required_vcs_complete(after)
120 assert docs_preserved(before, after)
121 assert after.docs.handover == before.docs.handover
122 assert after.docs.roadmap == before.docs.roadmap
123 assert after.vcs.git.mirror_branch == "muse-mirror"
124 assert after.vcs.muse.staging_remote == "staging"
125
126
127 def test_silent_regime_only_patch_detector() -> None:
128 before = _load_muse_only()
129 silent = {
130 "vcs": {
131 "regime": "muse+git-mirror",
132 "canonical": "muse",
133 "git": {"remote": "origin", "main_branch": "main", "mirror_branch": None},
134 "muse": {"staging_remote": None, "main_branch": "main"},
135 }
136 }
137 assert is_silent_regime_only_patch(before, silent) is True
138 good = build_upgraded_config_dict(before)
139 assert is_silent_regime_only_patch(before, good) is False
140
141
142 def test_g3_g6_helpers_on_fixture_script() -> None:
143 config = load_config(FIXTURES / "config-muse-git-mirror.yaml")
144 script = render_template(
145 kit_root() / "templates" / "scripts" / "muse-bridge-deploy.sh.template",
146 config,
147 )
148 assert check_g3_deploy_script(script).ok
149 assert check_g4_deploy_script(script).ok
150 assert check_g5_deploy_script(script).ok
151 assert check_g6_deploy_script(script).ok
152
153 bad_push = script.replace(
154 'push "${GIT_REMOTE}" "${MIRROR_BRANCH}"',
155 "git push origin main",
156 )
157 assert not check_g4_deploy_script(bad_push).ok
158
159 home = script + "\n# /Users/operator/secret\n"
160 assert not check_g6_deploy_script(home).ok
161
162
163 def test_g8_remote_helper() -> None:
164 runner = make_runner({"git remote get-url origin": ok("[email protected]:owner/repo.git")})
165 assert check_g8_git_remote(Path("/tmp"), "origin", runner).ok
166
167 runner_empty = make_runner(
168 {"git remote get-url origin": CommandResult(stdout="", stderr="", exit_code=0)}
169 )
170 assert not check_g8_git_remote(Path("/tmp"), "origin", runner_empty).ok
File History 1 commit
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 2 days ago