gabriel / muse public
test_stress_e2e_workflow.py python
276 lines 9.6 KB
Raw
sha256:1d3f5470f45db58e32047678debc9438fdded1b2c7332cc743d2b8be32fdafc8 fixing more broken tests Human patch 2 days ago
1 """End-to-end CLI stress tests — mission-critical workflow verification.
2
3 Tests the full muse CLI lifecycle using CliRunner with monkeypatch.chdir:
4 init → commit → log → branch → checkout → merge → tag → revert → shelf
5
6 Adversarial scenarios:
7 - 50-commit linear history: log shows all, branch creates correctly.
8 - Concurrent agent commits with provenance fields.
9 - Branch → commit → merge full cycle.
10 - Annotate accumulates reviewers (ORSet semantics).
11 - Shelf save and pop.
12 - Revert commit.
13 - Reset.
14 """
15
16 import pathlib
17
18 import pytest
19 from tests.cli_test_helper import CliRunner
20
21 cli = None # argparse migration — CliRunner ignores this arg
22
23 runner = CliRunner()
24
25
26 # ---------------------------------------------------------------------------
27 # Helpers
28 # ---------------------------------------------------------------------------
29
30
31 def _run(*args: str) -> tuple[int, str]:
32 result = runner.invoke(cli, list(args), catch_exceptions=False)
33 return result.exit_code, result.output
34
35
36 def _write_file(repo: pathlib.Path, filename: str, content: str = "code = True\n") -> None:
37 work = repo
38 (work / filename).write_text(content)
39
40
41 @pytest.fixture
42 def repo(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> pathlib.Path:
43 monkeypatch.chdir(tmp_path)
44 monkeypatch.setenv("MUSE_REPO_ROOT", str(tmp_path))
45 code, out = _run("init", "--domain", "code")
46 assert code == 0, f"init failed: {out}"
47 return tmp_path
48
49
50 # ===========================================================================
51 # Basic lifecycle
52 # ===========================================================================
53
54
55 class TestBasicLifecycle:
56 def test_init_creates_muse_dir(self, tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> None:
57 monkeypatch.chdir(tmp_path)
58 code, _ = _run("init")
59 assert code == 0
60 assert (tmp_path / ".muse").is_dir()
61
62 def test_commit_and_log(self, repo: pathlib.Path) -> None:
63 _write_file(repo, "main.py", "x = 1\n")
64 code, out = _run("commit", "-m", "first commit")
65 assert code == 0
66
67 code2, log_out = _run("log")
68 assert code2 == 0
69 assert "first commit" in log_out
70
71 def test_status_works(self, repo: pathlib.Path) -> None:
72 _write_file(repo, "app.py", "print('hello')\n")
73 code, out = _run("status")
74 assert code == 0
75
76 def test_tag_commit(self, repo: pathlib.Path) -> None:
77 _write_file(repo, "tagged.py", "tagged = True\n")
78 _run("commit", "-m", "commit to tag")
79 code, out = _run("tag", "add", "v1.0.0")
80 assert code == 0
81
82 def test_log_shows_multiple_commits(self, repo: pathlib.Path) -> None:
83 for i in range(5):
84 _write_file(repo, f"file{i}.py", f"x = {i}\n")
85 _run("code", "add", ".")
86 _run("commit", "-m", f"commit number {i}")
87
88 code, out = _run("log")
89 assert code == 0
90 for i in range(5):
91 assert f"commit number {i}" in out
92
93 def test_show_commit(self, repo: pathlib.Path) -> None:
94 _write_file(repo, "show_me.py", "show = 'this'\n")
95 _run("commit", "-m", "showable commit")
96 code, _ = _run("log")
97 assert code == 0
98
99
100 # ===========================================================================
101 # Branch and checkout
102 # ===========================================================================
103
104
105 class TestBranchAndCheckout:
106 def test_branch_creation(self, repo: pathlib.Path) -> None:
107 _write_file(repo, "base.py", "base = 1\n")
108 _run("commit", "-m", "base commit")
109 code, out = _run("branch", "feature/new-thing")
110 assert code == 0
111
112 def test_checkout_to_new_branch_then_back(self, repo: pathlib.Path) -> None:
113 _write_file(repo, "common.py", "common = 1\n")
114 _run("commit", "-m", "initial")
115
116 _run("branch", "feature")
117 code, _ = _run("checkout", "feature")
118 assert code == 0
119 code3, _ = _run("checkout", "main")
120 assert code3 == 0
121
122 def test_multiple_branches_independent(self, repo: pathlib.Path) -> None:
123 _write_file(repo, "root.py", "root = True\n")
124 _run("commit", "-m", "root")
125
126 for i in range(3):
127 _run("branch", f"branch-{i}")
128 code, out = _run("checkout", f"branch-{i}")
129 assert code == 0, f"checkout branch-{i} failed: {out}"
130 _write_file(repo, f"branch_{i}.py", f"b = {i}\n")
131 _run("commit", "-m", f"branch-{i} commit")
132 _run("checkout", "main")
133
134
135 # ===========================================================================
136 # Shelf
137 # ===========================================================================
138
139
140 class TestShelf:
141 def test_shelf_save_and_pop(self, repo: pathlib.Path) -> None:
142 _write_file(repo, "base.py", "base = True\n")
143 _run("commit", "-m", "before shelf")
144
145 _write_file(repo, "unstaged.py", "unstaged = True\n")
146 code, out = _run("shelf", "save")
147 assert code == 0, f"shelf save failed: {out}"
148
149 code2, out2 = _run("shelf", "pop")
150 assert code2 == 0, f"shelf pop failed: {out2}"
151
152
153 # ===========================================================================
154 # Revert
155 # ===========================================================================
156
157
158 class TestRevert:
159 def test_revert_undoes_last_commit(self, repo: pathlib.Path) -> None:
160 _write_file(repo, "original.py", "original = True\n")
161 _run("code", "add", ".")
162 _run("commit", "-m", "original state")
163 _write_file(repo, "added.py", "added = True\n")
164 _run("code", "add", ".")
165 _run("commit", "-m", "added something")
166
167 code, out = _run("log")
168 assert "added something" in out
169
170 code2, _ = _run("revert", "HEAD")
171 assert code2 == 0
172
173
174 # ===========================================================================
175 # Reset
176 # ===========================================================================
177
178
179 class TestReset:
180 def test_soft_reset_to_head(self, repo: pathlib.Path) -> None:
181 """Reset to HEAD (soft) — a no-op but must not fail."""
182 _write_file(repo, "file.py", "x = 1\n")
183 code1, out1 = _run("commit", "-m", "commit 1")
184 assert code1 == 0
185
186 # "HEAD" is accepted by resolve_commit_ref as the current commit.
187 # Options must precede the positional REF argument in Typer sub-typers.
188 code, out = _run("reset", "--soft", "HEAD")
189 assert code == 0, f"reset failed: {out}"
190
191
192 # ===========================================================================
193 # Provenance fields in commit
194 # ===========================================================================
195
196
197 class TestProvenanceCommit:
198 def test_commit_with_agent_id(self, repo: pathlib.Path) -> None:
199 _write_file(repo, "agent.py", "agent = True\n")
200 result = runner.invoke(
201 cli,
202 ["commit", "-m", "agent commit", "--agent-id", "test-agent"],
203 catch_exceptions=False,
204 )
205 assert result.exit_code == 0
206
207 def test_commit_with_model_id(self, repo: pathlib.Path) -> None:
208 _write_file(repo, "model.py", "model = 'gpt-4o'\n")
209 result = runner.invoke(
210 cli,
211 ["commit", "-m", "model commit", "--model-id", "gpt-4o"],
212 catch_exceptions=False,
213 )
214 assert result.exit_code == 0
215
216
217 # ===========================================================================
218 # Annotate command
219 # ===========================================================================
220
221
222 class TestAnnotateCommand:
223 def test_annotate_test_run(self, repo: pathlib.Path) -> None:
224 _write_file(repo, "annotate_me.py", "code = True\n")
225 _run("commit", "-m", "to annotate")
226 code, out = _run("annotate", "--test-run")
227 assert code == 0
228
229 def test_annotate_reviewed_by(self, repo: pathlib.Path) -> None:
230 _write_file(repo, "reviewed.py", "reviewed = True\n")
231 _run("commit", "-m", "for review")
232 code, out = _run("annotate", "--reviewed-by", "alice")
233 assert code == 0
234
235 def test_annotate_accumulates_reviewers(self, repo: pathlib.Path) -> None:
236 _write_file(repo, "multi_review.py", "x = 1\n")
237 _run("commit", "-m", "multi-review")
238 _run("annotate", "--reviewed-by", "alice")
239 code, out = _run("annotate", "--reviewed-by", "bob")
240 assert code == 0
241
242
243 # ===========================================================================
244 # Long workflow stress
245 # ===========================================================================
246
247
248 class TestLongWorkflowStress:
249 def test_50_sequential_commits(self, repo: pathlib.Path) -> None:
250 for i in range(50):
251 _write_file(repo, f"module_{i:03d}.py", f"x = {i}\n")
252 _run("code", "add", ".")
253 code, out = _run("commit", "-m", f"commit {i:03d}")
254 assert code == 0, f"commit {i} failed: {out}"
255
256 code, out = _run("log")
257 assert code == 0
258 assert "commit 000" in out
259 assert "commit 049" in out
260
261 def test_branch_commit_merge_cycle(self, repo: pathlib.Path) -> None:
262 """Full branch → commit → merge cycle."""
263 _write_file(repo, "main.py", "main = True\n")
264 _run("commit", "-m", "main base")
265
266 _run("branch", "feature/thing")
267 _run("checkout", "feature/thing")
268 _write_file(repo, "feature.py", "feature = True\n")
269 _run("code", "add", ".")
270 code, out = _run("commit", "-m", "feature work")
271 assert code == 0
272
273 _run("checkout", "main")
274 code2, out2 = _run("merge", "feature/thing")
275 # Merge may succeed or report no commits yet — either way must not crash.
276 assert code2 in (0, 1), f"merge crashed: {out2}"
File History 1 commit
sha256:1d3f5470f45db58e32047678debc9438fdded1b2c7332cc743d2b8be32fdafc8 fixing more broken tests Human patch 2 days ago