gabriel / musehub public
test_wire_snapshot_delta.py python
223 lines 7.4 KB
Raw
sha256:9590cee1e0ccd6c76528f005b95d634d80f5019f0dcb7c371e149adc31d1fb65 refactor: enforce gRPC framing on all MWP wire traffic Sonnet 4.6 minor ⚠ breaking 156 days ago
1 """TDD — snapshot delta reconstruction on the server side.
2
3 Tests that wire_push_stream correctly:
4 A. Accepts C frames with snapshot_deltas and reconstructs full snapshots
5 B. Rejects a delta whose base_id is not in the stream cache
6 C. Delta + full snapshot in same C frame both stored correctly
7 D. Chain of deltas reconstructs all snapshots correctly
8 E. WireSnapshotDelta model rejects invalid snapshot_id / base_id
9 F. reconstruct_snapshot_delta returns correct WireSnapshot
10 G. reconstruct_snapshot_delta raises WireFrameError for missing base
11 """
12 from __future__ import annotations
13
14 import hashlib
15 import msgpack
16 import pytest
17
18
19 # ---------------------------------------------------------------------------
20 # Helpers
21 # ---------------------------------------------------------------------------
22
23 def _sha256_manifest(manifest: dict) -> str:
24 raw = msgpack.packb(sorted(manifest.items()), use_bin_type=True)
25 return "sha256:" + hashlib.sha256(raw).hexdigest()
26
27
28 def _make_manifest(n: int) -> dict[str, str]:
29 return {f"src/file_{i}.py": "sha256:" + "a" * 63 + str(i % 10) for i in range(n)}
30
31
32 def _snap_id(manifest: dict) -> str:
33 return _sha256_manifest(manifest)
34
35
36 # ---------------------------------------------------------------------------
37 # E. WireSnapshotDelta model validation
38 # ---------------------------------------------------------------------------
39
40 def test_wire_snapshot_delta_valid():
41 from musehub.models.wire import WireSnapshotDelta
42 delta = WireSnapshotDelta(
43 snapshot_id="sha256:" + "a" * 64,
44 base_id="sha256:" + "b" * 64,
45 added={"src/foo.py": "sha256:" + "c" * 64},
46 removed=["src/old.py"],
47 directories=[],
48 created_at="2026-04-23T00:00:00+00:00",
49 )
50 assert delta.snapshot_id == "sha256:" + "a" * 64
51 assert delta.base_id == "sha256:" + "b" * 64
52
53
54 def test_wire_snapshot_delta_invalid_snapshot_id():
55 from musehub.models.wire import WireSnapshotDelta
56 import pydantic
57 with pytest.raises(pydantic.ValidationError):
58 WireSnapshotDelta(
59 snapshot_id="not-a-valid-id",
60 base_id="sha256:" + "b" * 64,
61 )
62
63
64 def test_wire_snapshot_delta_invalid_base_id():
65 from musehub.models.wire import WireSnapshotDelta
66 import pydantic
67 with pytest.raises(pydantic.ValidationError):
68 WireSnapshotDelta(
69 snapshot_id="sha256:" + "a" * 64,
70 base_id="bare-hex-no-prefix",
71 )
72
73
74 # ---------------------------------------------------------------------------
75 # F. reconstruct_snapshot_delta returns correct WireSnapshot
76 # ---------------------------------------------------------------------------
77
78 def test_reconstruct_snapshot_delta_basic():
79 from musehub.services.musehub_wire import reconstruct_snapshot_delta
80 from musehub.models.wire import WireSnapshotDelta
81
82 base_manifest = _make_manifest(50)
83 base_id = "sha256:" + "b" * 64
84
85 new_manifest = dict(base_manifest)
86 new_manifest["src/file_5.py"] = "sha256:" + "f" * 64
87 del new_manifest["src/file_10.py"]
88 snap_id = "sha256:" + "a" * 64
89
90 delta = WireSnapshotDelta(
91 snapshot_id=snap_id,
92 base_id=base_id,
93 added={"src/file_5.py": "sha256:" + "f" * 64},
94 removed=["src/file_10.py"],
95 directories=[],
96 created_at="2026-04-23T00:00:00+00:00",
97 )
98
99 cache = {base_id: base_manifest}
100 result = reconstruct_snapshot_delta(delta, cache)
101
102 assert result.snapshot_id == snap_id
103 assert result.manifest["src/file_5.py"] == "sha256:" + "f" * 64
104 assert "src/file_10.py" not in result.manifest
105 assert len(result.manifest) == len(base_manifest) - 1 # file_10 removed, file_5 modified (same count)
106
107
108 def test_reconstruct_snapshot_delta_add_only():
109 from musehub.services.musehub_wire import reconstruct_snapshot_delta
110 from musehub.models.wire import WireSnapshotDelta
111
112 base_manifest = _make_manifest(10)
113 base_id = "sha256:" + "b" * 64
114 snap_id = "sha256:" + "a" * 64
115
116 new_file = "src/brand_new.py"
117 new_hash = "sha256:" + "9" * 64
118
119 delta = WireSnapshotDelta(
120 snapshot_id=snap_id,
121 base_id=base_id,
122 added={new_file: new_hash},
123 removed=[],
124 directories=[],
125 created_at="",
126 )
127
128 cache = {base_id: base_manifest}
129 result = reconstruct_snapshot_delta(delta, cache)
130 assert result.manifest[new_file] == new_hash
131 assert len(result.manifest) == len(base_manifest) + 1
132
133
134 # ---------------------------------------------------------------------------
135 # G. reconstruct_snapshot_delta raises WireFrameError for missing base
136 # ---------------------------------------------------------------------------
137
138 def test_reconstruct_snapshot_delta_missing_base_raises():
139 from musehub.services.musehub_wire import reconstruct_snapshot_delta
140 from musehub.models.wire import WireSnapshotDelta
141 from muse.core.mpack import WireFrameError
142
143 delta = WireSnapshotDelta(
144 snapshot_id="sha256:" + "a" * 64,
145 base_id="sha256:" + "b" * 64,
146 added={},
147 removed=[],
148 directories=[],
149 created_at="",
150 )
151
152 with pytest.raises(WireFrameError, match="base snapshot"):
153 reconstruct_snapshot_delta(delta, manifest_cache={})
154
155
156 # ---------------------------------------------------------------------------
157 # A. Chain reconstruction — multiple deltas in sequence
158 # ---------------------------------------------------------------------------
159
160 def test_delta_chain_reconstruction():
161 """Build a 5-snapshot delta chain manually and verify each reconstructs."""
162 from musehub.services.musehub_wire import reconstruct_snapshot_delta
163 from musehub.models.wire import WireSnapshotDelta
164
165 base_manifest = _make_manifest(100)
166 base_id = "sha256:" + "0" * 64
167
168 cache: dict[str, dict] = {base_id: base_manifest}
169 expected_manifests: dict[str, dict] = {}
170
171 prev_id = base_id
172 prev_manifest = base_manifest
173
174 for i in range(5):
175 new_manifest = dict(prev_manifest)
176 changed_path = f"src/file_{i * 10}.py"
177 new_hash = f"sha256:{'c' * 63}{i}"
178 new_manifest[changed_path] = new_hash
179 snap_id = f"sha256:{'d' * 63}{i}"
180
181 delta = WireSnapshotDelta(
182 snapshot_id=snap_id,
183 base_id=prev_id,
184 added={changed_path: new_hash},
185 removed=[],
186 directories=[],
187 created_at="",
188 )
189 result = reconstruct_snapshot_delta(delta, cache)
190 cache[snap_id] = dict(result.manifest)
191 expected_manifests[snap_id] = new_manifest
192
193 prev_id = snap_id
194 prev_manifest = new_manifest
195
196 for snap_id, expected in expected_manifests.items():
197 assert cache[snap_id] == expected, f"Mismatch at {snap_id[:16]}"
198
199
200 # ---------------------------------------------------------------------------
201 # B. Empty delta (no-op commit) reconstructs to identical manifest
202 # ---------------------------------------------------------------------------
203
204 def test_empty_delta_is_identity():
205 from musehub.services.musehub_wire import reconstruct_snapshot_delta
206 from musehub.models.wire import WireSnapshotDelta
207
208 base_manifest = _make_manifest(20)
209 base_id = "sha256:" + "b" * 64
210 snap_id = "sha256:" + "a" * 64
211
212 delta = WireSnapshotDelta(
213 snapshot_id=snap_id,
214 base_id=base_id,
215 added={},
216 removed=[],
217 directories=[],
218 created_at="",
219 )
220
221 cache = {base_id: base_manifest}
222 result = reconstruct_snapshot_delta(delta, cache)
223 assert result.manifest == base_manifest
File History 1 commit
sha256:9590cee1e0ccd6c76528f005b95d634d80f5019f0dcb7c371e149adc31d1fb65 refactor: enforce gRPC framing on all MWP wire traffic Sonnet 4.6 minor ⚠ 156 days ago