test_wire_snapshot_delta.py
python
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