gabriel / muse public
test_core_query_engine.py python
553 lines 22.0 KB
Raw
sha256:660fcac1df3ab28f61862e961890bd2ca8b754fa0242079d93ca1e25037ec8a6 chore(tests): add docstring to tests/__init__.py so rc14 tr… Human 26 days ago
1 """Tests for the generic query engine in muse/core/query_engine.py.
2
3 Also contains regression tests that prove the two dead walkers in
4 ``muse.plugins.code._query`` (``walk_commits`` and ``walk_commits_range``) are
5 fully covered by the live walkers (``walk_commits_bfs`` and
6 ``store.walk_commits_between``) before those dead functions are deleted.
7 """
8
9 import datetime
10 import pathlib
11 import tempfile
12
13 import pytest
14
15 from muse.core.query_engine import QueryMatch, format_matches, walk_history
16 from muse.core.snapshot import compute_commit_id, compute_snapshot_id
17 from muse.core.store import CommitRecord, write_commit, walk_commits_between
18 from muse.plugins.code._query import walk_commits_bfs
19 from muse.core._types import Manifest
20
21
22 # ---------------------------------------------------------------------------
23 # Helpers
24 # ---------------------------------------------------------------------------
25
26
27 def _make_repo(tmp_path: pathlib.Path) -> pathlib.Path:
28 """Set up a minimal .muse/ structure for query_engine tests."""
29 muse = tmp_path / ".muse"
30 muse.mkdir()
31 (muse / "repo.json").write_text('{"repo_id":"test-repo"}')
32 (muse / "HEAD").write_text("ref: refs/heads/main")
33 (muse / "commits").mkdir()
34 (muse / "snapshots").mkdir()
35 (muse / "refs" / "heads").mkdir(parents=True)
36 return tmp_path
37
38
39 def _write_commit(root: pathlib.Path, label: str, parent_id: str | None = None) -> CommitRecord:
40 """Write a content-addressed CommitRecord. *label* is used only in the message."""
41 snap_id = compute_snapshot_id({})
42 committed_at = datetime.datetime.now(datetime.timezone.utc)
43 parent_ids = [parent_id] if parent_id else []
44 commit_id = compute_commit_id(parent_ids, snap_id, f"commit {label}", committed_at.isoformat())
45 record = CommitRecord(
46 commit_id=commit_id,
47 repo_id="test-repo",
48 branch="main",
49 snapshot_id=snap_id,
50 message=f"commit {label}",
51 committed_at=committed_at,
52 parent_commit_id=parent_id,
53 author="test-author",
54 )
55 write_commit(root, record)
56 return record
57
58
59 # ---------------------------------------------------------------------------
60 # walk_history
61 # ---------------------------------------------------------------------------
62
63
64 class TestWalkHistory:
65 def test_empty_branch_returns_empty(self) -> None:
66 with tempfile.TemporaryDirectory() as tmp:
67 root = _make_repo(pathlib.Path(tmp))
68 results = walk_history(root, "main", lambda c, m, r: [])
69 assert results == []
70
71 def test_single_commit_visited(self) -> None:
72 with tempfile.TemporaryDirectory() as tmp:
73 root = _make_repo(pathlib.Path(tmp))
74 c = _write_commit(root, "aaa111")
75 (root / ".muse" / "refs" / "heads" / "main").write_text(c.commit_id)
76
77 visited: list[str] = []
78
79 def evaluator(commit: CommitRecord, manifest: Manifest, r: pathlib.Path) -> list[QueryMatch]:
80 visited.append(commit.commit_id)
81 return []
82
83 walk_history(root, "main", evaluator, load_manifest=False)
84 assert visited == [c.commit_id]
85
86 def test_chain_walked_newest_first(self) -> None:
87 with tempfile.TemporaryDirectory() as tmp:
88 root = _make_repo(pathlib.Path(tmp))
89 c_aaa = _write_commit(root, "aaa111")
90 c_bbb = _write_commit(root, "bbb222", parent_id=c_aaa.commit_id)
91 (root / ".muse" / "refs" / "heads" / "main").write_text(c_bbb.commit_id)
92
93 visited: list[str] = []
94
95 def evaluator(commit: CommitRecord, manifest: Manifest, r: pathlib.Path) -> list[QueryMatch]:
96 visited.append(commit.commit_id)
97 return []
98
99 walk_history(root, "main", evaluator, load_manifest=False)
100 assert visited == [c_bbb.commit_id, c_aaa.commit_id]
101
102 def test_matches_collected(self) -> None:
103 with tempfile.TemporaryDirectory() as tmp:
104 root = _make_repo(pathlib.Path(tmp))
105 c = _write_commit(root, "ccc333")
106 (root / ".muse" / "refs" / "heads" / "main").write_text(c.commit_id)
107
108 def evaluator(commit: CommitRecord, manifest: Manifest, r: pathlib.Path) -> list[QueryMatch]:
109 return [QueryMatch(
110 commit_id=commit.commit_id,
111 author=commit.author,
112 committed_at=commit.committed_at.isoformat(),
113 branch=commit.branch,
114 detail="test match",
115 extra={},
116 )]
117
118 results = walk_history(root, "main", evaluator, load_manifest=False)
119 assert len(results) == 1
120 assert results[0]["detail"] == "test match"
121
122 def test_max_commits_limits_walk(self) -> None:
123 with tempfile.TemporaryDirectory() as tmp:
124 root = _make_repo(pathlib.Path(tmp))
125 records: list[CommitRecord] = []
126 for i in range(10):
127 parent_id = records[i - 1].commit_id if i > 0 else None
128 records.append(_write_commit(root, f"commit{i:03d}", parent_id=parent_id))
129 (root / ".muse" / "refs" / "heads" / "main").write_text(records[-1].commit_id)
130
131 visited: list[str] = []
132
133 def evaluator(commit: CommitRecord, manifest: Manifest, r: pathlib.Path) -> list[QueryMatch]:
134 visited.append(commit.commit_id)
135 return []
136
137 walk_history(root, "main", evaluator, max_commits=3, load_manifest=False)
138 assert len(visited) == 3
139
140 def test_head_commit_id_override(self) -> None:
141 with tempfile.TemporaryDirectory() as tmp:
142 root = _make_repo(pathlib.Path(tmp))
143 c_aaa = _write_commit(root, "aaa111")
144 c_bbb = _write_commit(root, "bbb222", parent_id=c_aaa.commit_id)
145 # HEAD points to bbb222 but we override to aaa111.
146 (root / ".muse" / "refs" / "heads" / "main").write_text(c_bbb.commit_id)
147
148 visited: list[str] = []
149
150 def evaluator(commit: CommitRecord, manifest: Manifest, r: pathlib.Path) -> list[QueryMatch]:
151 visited.append(commit.commit_id)
152 return []
153
154 walk_history(root, "main", evaluator, head_commit_id=c_aaa.commit_id, load_manifest=False)
155 assert visited == [c_aaa.commit_id]
156
157
158 # ---------------------------------------------------------------------------
159 # format_matches
160 # ---------------------------------------------------------------------------
161
162
163 class TestFormatMatches:
164 def test_empty_returns_no_matches(self) -> None:
165 assert "No matches" in format_matches([])
166
167 def test_single_match_formatted(self) -> None:
168 m = QueryMatch(
169 commit_id="a" * 64,
170 author="gabriel",
171 committed_at="2026-03-18T12:00:00+00:00",
172 branch="main",
173 detail="my_function (added)",
174 extra={},
175 )
176 out = format_matches([m])
177 assert ("a" * 64)[:8] in out
178 assert "gabriel" in out
179 assert "my_function (added)" in out
180
181 def test_agent_id_shown_when_present(self) -> None:
182 m = QueryMatch(
183 commit_id="a" * 64,
184 author="bot",
185 committed_at="2026-03-18T12:00:00+00:00",
186 branch="main",
187 detail="something",
188 extra={},
189 agent_id="claude-v4",
190 )
191 out = format_matches([m])
192 assert "claude-v4" in out
193
194 def test_max_results_truncation_message_updated(self) -> None:
195 """format_matches uses '--limit' in the truncation hint (not '--max')."""
196 matches = [
197 QueryMatch(
198 commit_id=f"commit{i:04d}",
199 author="x",
200 committed_at="2026-01-01T00:00:00+00:00",
201 branch="main",
202 detail=f"match {i}",
203 extra={},
204 )
205 for i in range(10)
206 ]
207 out = format_matches(matches, max_results=5)
208 assert "--limit" in out
209
210 def test_max_results_capped(self) -> None:
211 matches = [
212 QueryMatch(
213 commit_id=f"commit{i:04d}",
214 author="x",
215 committed_at="2026-01-01T00:00:00+00:00",
216 branch="main",
217 detail=f"match {i}",
218 extra={},
219 )
220 for i in range(100)
221 ]
222 out = format_matches(matches, max_results=5)
223 assert "95 more" in out
224
225
226 # ---------------------------------------------------------------------------
227 # Regression tests: dead walkers covered by live walkers
228 #
229 # These tests prove that walk_commits_bfs and store.walk_commits_between
230 # fully cover the use-cases of the dead walk_commits and walk_commits_range
231 # before those functions are deleted. If these tests pass, deletion is safe.
232 # ---------------------------------------------------------------------------
233
234
235 def _make_repo_for_walker(tmp_path: pathlib.Path) -> pathlib.Path:
236 muse = tmp_path / ".muse"
237 muse.mkdir()
238 (muse / "repo.json").write_text('{"repo_id":"walker-test"}')
239 (muse / "HEAD").write_text("main")
240 (muse / "commits").mkdir()
241 (muse / "snapshots").mkdir()
242 (muse / "refs" / "heads").mkdir(parents=True)
243 return tmp_path
244
245
246 def _commit(
247 root: pathlib.Path,
248 label: str,
249 parent: str | None = None,
250 parent2: str | None = None,
251 ) -> CommitRecord:
252 """Write a content-addressed CommitRecord. *label* is used only in the message."""
253 snap_id = compute_snapshot_id({})
254 committed_at = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc)
255 parent_ids = [p for p in [parent, parent2] if p is not None]
256 commit_id = compute_commit_id(parent_ids, snap_id, f"msg {label}", committed_at.isoformat())
257 rec = CommitRecord(
258 commit_id=commit_id,
259 repo_id="walker-test",
260 branch="main",
261 snapshot_id=snap_id,
262 message=f"msg {label}",
263 committed_at=committed_at,
264 parent_commit_id=parent,
265 parent2_commit_id=parent2,
266 author="tester",
267 )
268 write_commit(root, rec)
269 return rec
270
271
272 class TestWalkHistoryFollowMerges:
273 """Belt-and-suspenders tests for walk_history(follow_merges=True/False)."""
274
275 def test_follow_merges_false_skips_parent2(
276 self, tmp_path: pathlib.Path
277 ) -> None:
278 """follow_merges=False (default) stays on the main parent chain only."""
279 root = _make_repo_for_walker(tmp_path)
280 c_main1 = _commit(root, "main1")
281 c_feat1 = _commit(root, "feat1", parent=c_main1.commit_id)
282 c_merge = _commit(root, "merge_c", parent=c_main1.commit_id, parent2=c_feat1.commit_id)
283 (root / ".muse" / "refs" / "heads" / "main").write_text(c_merge.commit_id)
284
285 visited: list[str] = []
286
287 def ev(c: CommitRecord, m: Manifest, r: pathlib.Path) -> list[QueryMatch]:
288 visited.append(c.commit_id)
289 return []
290
291 walk_history(root, "main", ev, follow_merges=False, load_manifest=False)
292 assert c_feat1.commit_id not in visited
293 assert c_merge.commit_id in visited
294 assert c_main1.commit_id in visited
295
296 def test_follow_merges_true_visits_parent2(
297 self, tmp_path: pathlib.Path
298 ) -> None:
299 """follow_merges=True visits both parents of a merge commit."""
300 root = _make_repo_for_walker(tmp_path)
301 c_base = _commit(root, "base")
302 c_feature = _commit(root, "feature", parent=c_base.commit_id)
303 c_merge = _commit(root, "merge_c", parent=c_base.commit_id, parent2=c_feature.commit_id)
304 (root / ".muse" / "refs" / "heads" / "main").write_text(c_merge.commit_id)
305
306 visited: list[str] = []
307
308 def ev(c: CommitRecord, m: Manifest, r: pathlib.Path) -> list[QueryMatch]:
309 visited.append(c.commit_id)
310 return []
311
312 walk_history(root, "main", ev, follow_merges=True, load_manifest=False)
313 assert set(visited) == {c_merge.commit_id, c_base.commit_id, c_feature.commit_id}
314
315 def test_follow_merges_true_linear_chain(
316 self, tmp_path: pathlib.Path
317 ) -> None:
318 """follow_merges=True on a linear chain behaves identically to False."""
319 root = _make_repo_for_walker(tmp_path)
320 c_a = _commit(root, "a")
321 c_b = _commit(root, "b", parent=c_a.commit_id)
322 c_c = _commit(root, "c", parent=c_b.commit_id)
323 (root / ".muse" / "refs" / "heads" / "main").write_text(c_c.commit_id)
324
325 visited_ff: list[str] = []
326 visited_ft: list[str] = []
327
328 def ev_ff(c: CommitRecord, m: Manifest, r: pathlib.Path) -> list[QueryMatch]:
329 visited_ff.append(c.commit_id)
330 return []
331
332 def ev_ft(c: CommitRecord, m: Manifest, r: pathlib.Path) -> list[QueryMatch]:
333 visited_ft.append(c.commit_id)
334 return []
335
336 walk_history(root, "main", ev_ff, follow_merges=False, load_manifest=False)
337 walk_history(root, "main", ev_ft, follow_merges=True, load_manifest=False)
338 assert set(visited_ff) == set(visited_ft) == {c_a.commit_id, c_b.commit_id, c_c.commit_id}
339
340 def test_follow_merges_since_filter_applies(
341 self, tmp_path: pathlib.Path
342 ) -> None:
343 """since filter still prunes commits even with follow_merges=True."""
344 root = _make_repo_for_walker(tmp_path)
345 # Pin explicit timestamps so since filter is deterministic.
346 t_old = datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc)
347 t_new = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc)
348
349 snap_id = compute_snapshot_id({})
350 cid_old = compute_commit_id([], snap_id, "old", t_old.isoformat())
351 rec_old = CommitRecord(
352 commit_id=cid_old,
353 repo_id="walker-test",
354 branch="main",
355 snapshot_id=snap_id,
356 message="old",
357 committed_at=t_old,
358 author="tester",
359 )
360 write_commit(root, rec_old)
361
362 cid_new = compute_commit_id([cid_old], snap_id, "new", t_new.isoformat())
363 rec_new = CommitRecord(
364 commit_id=cid_new,
365 repo_id="walker-test",
366 branch="main",
367 snapshot_id=snap_id,
368 message="new",
369 committed_at=t_new,
370 parent_commit_id=cid_old,
371 author="tester",
372 )
373 write_commit(root, rec_new)
374 (root / ".muse" / "refs" / "heads" / "main").write_text(cid_new)
375
376 visited: list[str] = []
377
378 def ev(c: CommitRecord, m: Manifest, r: pathlib.Path) -> list[QueryMatch]:
379 visited.append(c.commit_id)
380 return []
381
382 since = datetime.datetime(2025, 1, 1, tzinfo=datetime.timezone.utc)
383 walk_history(root, "main", ev, follow_merges=True, since=since, load_manifest=False)
384 assert cid_new in visited
385 assert cid_old not in visited
386
387
388 def test_follow_merges_true_diamond_dag_no_duplicates(
389 self, tmp_path: pathlib.Path
390 ) -> None:
391 """BFS never visits the same commit twice (diamond DAG case)."""
392 root = _make_repo_for_walker(tmp_path)
393 # Diamond: base ← left ← merge, base ← right ← merge
394 c_base = _commit(root, "base")
395 c_left = _commit(root, "left", parent=c_base.commit_id)
396 c_right = _commit(root, "right", parent=c_base.commit_id)
397 c_merge = _commit(root, "merge_c", parent=c_left.commit_id, parent2=c_right.commit_id)
398 (root / ".muse" / "refs" / "heads" / "main").write_text(c_merge.commit_id)
399
400 visited: list[str] = []
401
402 def ev(c: CommitRecord, m: Manifest, r: pathlib.Path) -> list[QueryMatch]:
403 visited.append(c.commit_id)
404 return []
405
406 walk_history(root, "main", ev, follow_merges=True, load_manifest=False)
407 # Each commit visited exactly once.
408 assert len(visited) == len(set(visited))
409 assert set(visited) == {c_base.commit_id, c_left.commit_id, c_right.commit_id, c_merge.commit_id}
410
411 def test_follow_merges_max_commits_respected(
412 self, tmp_path: pathlib.Path
413 ) -> None:
414 """max_commits caps BFS walk even with follow_merges=True."""
415 root = _make_repo_for_walker(tmp_path)
416 c1 = _commit(root, "c1")
417 c2 = _commit(root, "c2", parent=c1.commit_id)
418 c3 = _commit(root, "c3", parent=c2.commit_id)
419 c4 = _commit(root, "c4", parent=c3.commit_id)
420 (root / ".muse" / "refs" / "heads" / "main").write_text(c4.commit_id)
421
422 visited: list[str] = []
423
424 def ev(c: CommitRecord, m: Manifest, r: pathlib.Path) -> list[QueryMatch]:
425 visited.append(c.commit_id)
426 return []
427
428 walk_history(root, "main", ev, follow_merges=True, max_commits=2, load_manifest=False)
429 assert len(visited) == 2
430
431 def test_follow_merges_evaluator_sees_match(
432 self, tmp_path: pathlib.Path
433 ) -> None:
434 """Matches from parent2 commits are included in results."""
435 root = _make_repo_for_walker(tmp_path)
436 c_base = _commit(root, "base")
437 c_feature = _commit(root, "feature", parent=c_base.commit_id)
438 c_merge = _commit(root, "merge_c", parent=c_base.commit_id, parent2=c_feature.commit_id)
439 (root / ".muse" / "refs" / "heads" / "main").write_text(c_merge.commit_id)
440
441 def ev(c: CommitRecord, m: Manifest, r: pathlib.Path) -> list[QueryMatch]:
442 if c.commit_id == c_feature.commit_id:
443 return [QueryMatch(
444 commit_id=c.commit_id,
445 author=c.author,
446 committed_at=c.committed_at.isoformat(),
447 branch=c.branch,
448 detail="feature found",
449 extra={},
450 )]
451 return []
452
453 results = walk_history(root, "main", ev, follow_merges=True, load_manifest=False)
454 assert len(results) == 1
455 assert results[0]["detail"] == "feature found"
456
457 def test_follow_merges_false_misses_parent2_commit(
458 self, tmp_path: pathlib.Path
459 ) -> None:
460 """With follow_merges=False, parent2 commits are never evaluated."""
461 root = _make_repo_for_walker(tmp_path)
462 c_base = _commit(root, "base")
463 c_feature = _commit(root, "feature", parent=c_base.commit_id)
464 c_merge = _commit(root, "merge_c", parent=c_base.commit_id, parent2=c_feature.commit_id)
465 (root / ".muse" / "refs" / "heads" / "main").write_text(c_merge.commit_id)
466
467 def ev(c: CommitRecord, m: Manifest, r: pathlib.Path) -> list[QueryMatch]:
468 if c.commit_id == c_feature.commit_id:
469 return [QueryMatch(
470 commit_id=c.commit_id,
471 author=c.author,
472 committed_at=c.committed_at.isoformat(),
473 branch=c.branch,
474 detail="feature found",
475 extra={},
476 )]
477 return []
478
479 results = walk_history(root, "main", ev, follow_merges=False, load_manifest=False)
480 assert results == [] # feature commit is never visited
481
482
483 class TestLiveWalkersContracts:
484 """Regression: walk_commits_bfs and walk_commits_between cover deleted walkers.
485
486 These tests lock down the contracts of the surviving walkers, proving
487 the deleted walk_commits and walk_commits_range are fully superseded.
488 """
489
490 def test_walk_commits_bfs_linear_chain(self, tmp_path: pathlib.Path) -> None:
491 """walk_commits_bfs on a linear chain returns all commits, newest first."""
492 root = _make_repo_for_walker(tmp_path)
493 c_aaa = _commit(root, "aaa")
494 c_bbb = _commit(root, "bbb", parent=c_aaa.commit_id)
495 c_ccc = _commit(root, "ccc", parent=c_bbb.commit_id)
496
497 live_commits, truncated = walk_commits_bfs(root, c_ccc.commit_id)
498 live_ids = [c.commit_id for c in live_commits]
499
500 assert truncated is False
501 assert set(live_ids) == {c_aaa.commit_id, c_bbb.commit_id, c_ccc.commit_id}
502
503 def test_walk_commits_bfs_follows_parent2(self, tmp_path: pathlib.Path) -> None:
504 """walk_commits_bfs reaches parent2 branches — supersedes dead linear walker."""
505 root = _make_repo_for_walker(tmp_path)
506 c_base = _commit(root, "base")
507 c_feature = _commit(root, "feature", parent=c_base.commit_id)
508 c_merge = _commit(root, "merge_commit", parent=c_base.commit_id, parent2=c_feature.commit_id)
509
510 live_commits, _ = walk_commits_bfs(root, c_merge.commit_id)
511 live_ids = set(c.commit_id for c in live_commits)
512
513 assert c_feature.commit_id in live_ids
514 assert c_base.commit_id in live_ids
515 assert c_merge.commit_id in live_ids
516
517 def test_walk_commits_between_range(self, tmp_path: pathlib.Path) -> None:
518 """walk_commits_between excludes from_commit_id — supersedes walk_commits_range."""
519 root = _make_repo_for_walker(tmp_path)
520 c1 = _commit(root, "c1")
521 c2 = _commit(root, "c2", parent=c1.commit_id)
522 c3 = _commit(root, "c3", parent=c2.commit_id)
523 c4 = _commit(root, "c4", parent=c3.commit_id)
524
525 result = walk_commits_between(root, to_commit_id=c4.commit_id, from_commit_id=c1.commit_id)
526 ids = [c.commit_id for c in result]
527
528 assert ids == [c4.commit_id, c3.commit_id, c2.commit_id]
529 assert c1.commit_id not in ids
530
531 def test_walk_commits_between_none_from(self, tmp_path: pathlib.Path) -> None:
532 """walk_commits_between with from_commit_id=None returns entire chain."""
533 root = _make_repo_for_walker(tmp_path)
534 c_x1 = _commit(root, "x1")
535 c_x2 = _commit(root, "x2", parent=c_x1.commit_id)
536
537 ids = [c.commit_id for c in walk_commits_between(root, c_x2.commit_id, None)]
538 assert ids == [c_x2.commit_id, c_x1.commit_id]
539
540 def test_walk_commits_bfs_stop_at_excludes_boundary(
541 self, tmp_path: pathlib.Path
542 ) -> None:
543 """walk_commits_bfs stop_at_commit_id excludes the boundary — same contract as walk_commits_between."""
544 root = _make_repo_for_walker(tmp_path)
545 c_p1 = _commit(root, "p1")
546 c_p2 = _commit(root, "p2", parent=c_p1.commit_id)
547 c_p3 = _commit(root, "p3", parent=c_p2.commit_id)
548
549 bfs_commits, _ = walk_commits_bfs(root, c_p3.commit_id, stop_at_commit_id=c_p1.commit_id)
550 bfs_ids = [c.commit_id for c in bfs_commits]
551
552 assert c_p1.commit_id not in bfs_ids
553 assert set(bfs_ids) == {c_p3.commit_id, c_p2.commit_id}
File History 5 commits
sha256:660fcac1df3ab28f61862e961890bd2ca8b754fa0242079d93ca1e25037ec8a6 chore(tests): add docstring to tests/__init__.py so rc14 tr… Human 26 days ago
sha256:d8316ffae901be06347e16ab55be11868eb519dd16ade3e8aa16a99e662f7e62 baseline: rc14 re-baseline after rc3 store corruption recovery Human patch 26 days ago
sha256:50d413a635f57761c3fce1f70251b957b6423821525bf330747ef4007339222e Merge branch 'dev' into main Human 29 days ago
sha256:fb67fed5a4d3e40de84bdd163de94ef1386570bef1dd1a020a732c8a038962ce Merge branch 'dev' into main Human 48 days ago
sha256:1c4b3e3a9a1f300774c3ee662b572a698d5fd405bf765a71e6011a2e9c3eaaaa feat: Muse — version control for the agent era Human 100 days ago