gabriel / muse public
test_stress_store_provenance.py python
438 lines 15.7 KB
Raw
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 136 days ago
1 """Stress tests for CommitRecord, SnapshotRecord, TagRecord, and provenance fields.
2
3 Covers:
4 - CommitRecord round-trip through to_dict/from_dict for all format versions.
5 - format_version evolution: missing fields default correctly when reading old records.
6 - reviewed_by (ORSet semantics): list preserved, sorted, deduplicated via overwrite_commit.
7 - test_runs (GCounter semantics): monotonically increases via overwrite_commit.
8 - agent_id / model_id / toolchain_id / prompt_hash / signature fields.
9 - SnapshotRecord round-trip with large manifests.
10 - TagRecord round-trip.
11 - get_head_commit_id on empty branch returns None.
12 - write_commit is idempotent (won't overwrite).
13 - overwrite_commit updates the persisted record correctly.
14 - read_commit for absent commit returns None.
15 - list_commits and list_branches.
16 - list_tags returns all tags.
17 """
18
19 import datetime
20 import pathlib
21
22 import pytest
23
24 from muse.core._types import fake_id
25 from muse.core.crdts.or_set import ORSet
26 from muse.core.snapshot import compute_commit_id, compute_snapshot_id
27 from muse.domain import SemVerBump
28 from muse.core.store import (
29 CommitDict,
30 CommitRecord,
31 SnapshotRecord,
32 TagRecord,
33 get_all_commits,
34 get_all_tags,
35 get_head_commit_id,
36 overwrite_commit,
37 read_commit,
38 read_snapshot,
39 write_commit,
40 write_snapshot,
41 write_tag,
42 )
43
44
45 # ---------------------------------------------------------------------------
46 # Fixtures
47 # ---------------------------------------------------------------------------
48
49
50 @pytest.fixture
51 def repo(tmp_path: pathlib.Path) -> pathlib.Path:
52 muse = tmp_path / ".muse"
53 (muse / "commits").mkdir(parents=True)
54 (muse / "snapshots").mkdir(parents=True)
55 (muse / "tags").mkdir(parents=True)
56 (muse / "refs" / "heads").mkdir(parents=True)
57 return tmp_path
58
59
60 def _now() -> datetime.datetime:
61 return datetime.datetime.now(datetime.timezone.utc)
62
63
64 _SNAP_ID: str = compute_snapshot_id({})
65
66
67 def _commit(
68 label: str = "default",
69 branch: str = "main",
70 parent: str | None = None,
71 ) -> CommitRecord:
72 """Create a CommitRecord with a real content-addressed commit_id."""
73 committed_at = _now()
74 cid = compute_commit_id(
75 repo_id="test-repo",
76 parent_ids=[parent] if parent else [],
77 snapshot_id=_SNAP_ID,
78 message=f"commit {label}",
79 committed_at_iso=committed_at.isoformat(),
80 )
81 return CommitRecord(
82 commit_id=cid,
83 repo_id="test-repo",
84 created_on_branch=branch,
85 snapshot_id=_SNAP_ID,
86 message=f"commit {label}",
87 committed_at=committed_at,
88 parent_commit_id=parent,
89 )
90
91
92 # ===========================================================================
93 # CommitRecord round-trip
94 # ===========================================================================
95
96
97 class TestCommitRecordRoundTrip:
98 def test_minimal_round_trip(self) -> None:
99 c = _commit()
100 restored = CommitRecord.from_dict(c.to_dict())
101 assert restored.commit_id == c.commit_id
102 assert restored.created_on_branch == c.created_on_branch
103 assert restored.message == c.message
104
105 def test_all_provenance_fields_preserved(self) -> None:
106 c = CommitRecord(
107 commit_id="prov123",
108 repo_id=fake_id("repo"),
109 created_on_branch="main",
110 snapshot_id="snap",
111 message="provenance commit",
112 committed_at=_now(),
113 agent_id="claude-v4",
114 model_id="claude-3-5-sonnet",
115 toolchain_id="muse-cli-1.0",
116 prompt_hash="abc" * 10 + "ab",
117 signature="sig-" + "x" * 60,
118 signer_key_id="key-001",
119 )
120 d = c.to_dict()
121 restored = CommitRecord.from_dict(d)
122 assert restored.agent_id == "claude-v4"
123 assert restored.model_id == "claude-3-5-sonnet"
124 assert restored.toolchain_id == "muse-cli-1.0"
125 assert restored.signature == c.signature
126 assert restored.signer_key_id == "key-001"
127
128 def test_crdt_fields_preserved(self) -> None:
129 c = CommitRecord(
130 commit_id="crdt123",
131 repo_id=fake_id("repo"),
132 created_on_branch="main",
133 snapshot_id="snap",
134 message="crdt",
135 committed_at=_now(),
136 reviewed_by=["alice", "bob", "charlie"],
137 test_runs=42,
138 )
139 d = c.to_dict()
140 restored = CommitRecord.from_dict(d)
141 assert sorted(restored.reviewed_by) == ["alice", "bob", "charlie"]
142 assert restored.test_runs == 42
143
144 def test_sem_ver_bump_preserved(self) -> None:
145 bumps: tuple[SemVerBump, ...] = ("none", "patch", "minor", "major")
146 for bump in bumps:
147 c = CommitRecord(
148 commit_id="sv",
149 repo_id="r",
150 created_on_branch="main",
151 snapshot_id="s",
152 message="m",
153 committed_at=_now(),
154 sem_ver_bump=bump,
155 )
156 assert CommitRecord.from_dict(c.to_dict()).sem_ver_bump == bump
157
158 def test_breaking_changes_preserved(self) -> None:
159 c = CommitRecord(
160 commit_id="bc",
161 repo_id="r",
162 created_on_branch="main",
163 snapshot_id="s",
164 message="m",
165 committed_at=_now(),
166 breaking_changes=["removed `old_api`", "renamed `foo` → `bar`"],
167 )
168 restored = CommitRecord.from_dict(c.to_dict())
169 assert restored.breaking_changes == ["removed `old_api`", "renamed `foo` → `bar`"]
170
171 def test_parent_ids_preserved(self) -> None:
172 c = CommitRecord(
173 commit_id="merge",
174 repo_id="r",
175 created_on_branch="main",
176 snapshot_id="s",
177 message="m",
178 committed_at=_now(),
179 parent_commit_id="parent-1",
180 parent2_commit_id="parent-2",
181 )
182 restored = CommitRecord.from_dict(c.to_dict())
183 assert restored.parent_commit_id == "parent-1"
184 assert restored.parent2_commit_id == "parent-2"
185
186 def test_missing_crdt_fields_default_correctly(self) -> None:
187 """Simulates reading an older commit that lacks reviewed_by / test_runs."""
188 minimal: CommitDict = {
189 "commit_id": "old",
190 "repo_id": "r",
191 "created_on_branch": "main",
192 "snapshot_id": "snap",
193 "message": "old commit",
194 "committed_at": _now().isoformat(),
195 }
196 restored = CommitRecord.from_dict(minimal)
197 assert restored.reviewed_by == []
198 assert restored.test_runs == 0
199
200 def test_committed_at_timezone_aware(self) -> None:
201 c = _commit()
202 restored = CommitRecord.from_dict(c.to_dict())
203 assert restored.committed_at.tzinfo is not None
204
205
206 # ===========================================================================
207 # CommitRecord persistence
208 # ===========================================================================
209
210
211 class TestCommitPersistence:
212 def test_write_and_read_back(self, repo: pathlib.Path) -> None:
213 c = _commit("id001")
214 write_commit(repo, c)
215 restored = read_commit(repo, c.commit_id)
216 assert restored is not None
217 assert restored.commit_id == c.commit_id
218
219 def test_write_is_idempotent(self, repo: pathlib.Path) -> None:
220 c = _commit("id002")
221 write_commit(repo, c)
222 # Write the same commit again — the store must not corrupt it.
223 write_commit(repo, c)
224 restored = read_commit(repo, c.commit_id)
225 assert restored is not None
226 assert restored.message == c.message
227
228 def test_read_absent_commit_returns_none(self, repo: pathlib.Path) -> None:
229 assert read_commit(repo, fake_id("does-not-exist")) is None
230
231 def test_overwrite_commit_updates_reviewed_by(self, repo: pathlib.Path) -> None:
232 c = _commit("id003")
233 write_commit(repo, c)
234 # Simulate ORSet merge: add reviewer.
235 updated = read_commit(repo, c.commit_id)
236 assert updated is not None
237 updated.reviewed_by = ["agent-x", "human-bob"]
238 overwrite_commit(repo, updated)
239 restored = read_commit(repo, c.commit_id)
240 assert restored is not None
241 assert "agent-x" in restored.reviewed_by
242 assert "human-bob" in restored.reviewed_by
243
244 def test_overwrite_commit_updates_test_runs(self, repo: pathlib.Path) -> None:
245 c = _commit("id004")
246 write_commit(repo, c)
247 for expected in range(1, 6):
248 rec = read_commit(repo, c.commit_id)
249 assert rec is not None
250 rec.test_runs += 1
251 overwrite_commit(repo, rec)
252 after = read_commit(repo, c.commit_id)
253 assert after is not None
254 assert after.test_runs == expected
255
256 def test_list_commits_returns_all_written(self, repo: pathlib.Path) -> None:
257 commits = [_commit(f"c{i:04d}") for i in range(20)]
258 for c in commits:
259 write_commit(repo, c)
260 found = {c.commit_id for c in get_all_commits(repo)}
261 for c in commits:
262 assert c.commit_id in found
263
264 def test_many_commits_all_retrievable(self, repo: pathlib.Path) -> None:
265 real_ids: list[str] = []
266 prev: str | None = None
267 base_ts = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc)
268 for i in range(100):
269 committed_at = base_ts + datetime.timedelta(seconds=i)
270 cid = compute_commit_id(
271 repo_id="test-repo",
272 parent_ids=[prev] if prev else [],
273 snapshot_id=_SNAP_ID,
274 message=f"stress-{i:04d}",
275 committed_at_iso=committed_at.isoformat(),
276 )
277 write_commit(repo, CommitRecord(
278 commit_id=cid,
279 repo_id="test-repo",
280 created_on_branch="main",
281 snapshot_id=_SNAP_ID,
282 message=f"stress-{i:04d}",
283 committed_at=committed_at,
284 parent_commit_id=prev,
285 ))
286 real_ids.append(cid)
287 prev = cid
288 for cid in real_ids:
289 assert read_commit(repo, cid) is not None
290
291
292 # ===========================================================================
293 # SnapshotRecord
294 # ===========================================================================
295
296
297 class TestSnapshotRecordRoundTrip:
298 def test_minimal_round_trip(self) -> None:
299 s = SnapshotRecord(snapshot_id="snap-1", manifest={"f.mid": "hash1"})
300 restored = SnapshotRecord.from_dict(s.to_dict())
301 assert restored.snapshot_id == "snap-1"
302 assert restored.manifest == {"f.mid": "hash1"}
303
304 def test_large_manifest(self) -> None:
305 manifest = {f"track_{i:04d}.mid": f"hash-{i:064d}" for i in range(500)}
306 s = SnapshotRecord(snapshot_id="big-snap", manifest=manifest)
307 restored = SnapshotRecord.from_dict(s.to_dict())
308 assert len(restored.manifest) == 500
309 assert restored.manifest["track_0000.mid"] == f"hash-{0:064d}"
310
311 def test_write_and_read_back(self, repo: pathlib.Path) -> None:
312 manifest = {"a.mid": fake_id("a.mid-content"), "b.mid": fake_id("b.mid-content")}
313 snap_id = compute_snapshot_id(manifest)
314 s = SnapshotRecord(snapshot_id=snap_id, manifest=manifest)
315 write_snapshot(repo, s)
316 restored = read_snapshot(repo, snap_id)
317 assert restored is not None
318 assert restored.manifest == manifest
319
320 def test_empty_manifest_round_trip(self) -> None:
321 s = SnapshotRecord(snapshot_id="empty-snap", manifest={})
322 restored = SnapshotRecord.from_dict(s.to_dict())
323 assert restored.manifest == {}
324
325
326 # ===========================================================================
327 # TagRecord
328 # ===========================================================================
329
330
331 class TestTagRecord:
332 def test_round_trip(self) -> None:
333 t = TagRecord(
334 tag_id="tag-001",
335 repo_id=fake_id("repo"),
336 commit_id="abc123",
337 tag="v1.0.0",
338 )
339 restored = TagRecord.from_dict(t.to_dict())
340 assert restored.tag_id == "tag-001"
341 assert restored.tag == "v1.0.0"
342 assert restored.commit_id == "abc123"
343
344 def test_write_and_list(self, repo: pathlib.Path) -> None:
345 for i in range(10):
346 write_tag(repo, TagRecord(
347 tag_id=fake_id(f"tag-{i:04d}"),
348 repo_id=fake_id("repo"),
349 commit_id=fake_id(f"commit-{i:04d}"),
350 tag=f"v{i}.0.0",
351 ))
352 tags = get_all_tags(repo, fake_id("repo"))
353 assert len(tags) == 10
354
355 def test_created_at_preserved(self) -> None:
356 ts = datetime.datetime(2025, 6, 15, 12, 0, 0, tzinfo=datetime.timezone.utc)
357 t = TagRecord(tag_id="t", repo_id="r", commit_id="c", tag="v1", created_at=ts)
358 restored = TagRecord.from_dict(t.to_dict())
359 assert abs((restored.created_at - ts).total_seconds()) < 1.0
360
361
362 # ===========================================================================
363 # get_head_commit_id
364 # ===========================================================================
365
366
367 class TestGetHeadCommitId:
368 def test_empty_branch_returns_none(self, repo: pathlib.Path) -> None:
369 assert get_head_commit_id(repo, "nonexistent-branch") is None
370
371 def test_returns_id_after_writing_head_ref(self, repo: pathlib.Path) -> None:
372 ref_path = repo / ".muse" / "refs" / "heads" / "main"
373 ref_path.write_text("abc1234\n")
374 assert get_head_commit_id(repo, "main") == "abc1234"
375
376 def test_strips_whitespace(self, repo: pathlib.Path) -> None:
377 ref_path = repo / ".muse" / "refs" / "heads" / "feature"
378 ref_path.write_text(" deadbeef \n")
379 assert get_head_commit_id(repo, "feature") == "deadbeef"
380
381
382 # ===========================================================================
383 # CRDT semantics on CommitRecord fields
384 # ===========================================================================
385
386
387 class TestCRDTAnnotationSemantics:
388 def test_reviewed_by_orset_union_semantics(self, repo: pathlib.Path) -> None:
389 """ORSet union: multiple overwrite_commit calls accumulate reviewers."""
390 c = _commit("crdt-or-001")
391 write_commit(repo, c)
392
393 # Agent 1 adds their name.
394 rec = read_commit(repo, c.commit_id)
395 assert rec is not None
396 s, tok1 = ORSet().add("agent-alpha")
397 rec.reviewed_by = list(s.elements())
398 overwrite_commit(repo, rec)
399
400 # Agent 2 independently adds their name.
401 rec2 = read_commit(repo, c.commit_id)
402 assert rec2 is not None
403 s2 = ORSet()
404 for name in rec2.reviewed_by:
405 s2, _ = s2.add(name)
406 s2, tok2 = s2.add("agent-beta")
407 rec2.reviewed_by = sorted(s2.elements())
408 overwrite_commit(repo, rec2)
409
410 final = read_commit(repo, c.commit_id)
411 assert final is not None
412 assert "agent-alpha" in final.reviewed_by
413 assert "agent-beta" in final.reviewed_by
414
415 def test_test_runs_gcounter_monotone(self, repo: pathlib.Path) -> None:
416 """GCounter: test_runs must never decrease."""
417 c = _commit("crdt-gc-001")
418 write_commit(repo, c)
419 prev = 0
420 for _ in range(50):
421 rec = read_commit(repo, c.commit_id)
422 assert rec is not None
423 rec.test_runs += 1
424 overwrite_commit(repo, rec)
425 current = read_commit(repo, c.commit_id)
426 assert current is not None
427 assert current.test_runs >= prev
428 prev = current.test_runs
429 assert prev == 50
430
431 def test_all_provenance_fields_default_to_empty_string(self) -> None:
432 c = _commit()
433 assert c.agent_id == ""
434 assert c.model_id == ""
435 assert c.toolchain_id == ""
436 assert c.prompt_hash == ""
437 assert c.signature == ""
438 assert c.signer_key_id == ""
File History 3 commits
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 136 days ago
sha256:7f9e2ef5286aedad9c1e6011b4c46ca27f39dbdad6e3409357e36b26e46b3b7c docs: docstring sprint for-each-ref→hotspots — idiomatic ru… Sonnet 4.6 patch 142 days ago
sha256:a09b1b4f6838754495547f200aa0ce88e2f56ffc5b20b900f6f0cff2c3cdede9 fix(cursorignore): remove git-ism (.git/worktrees) Human minor 145 days ago