gabriel / muse public
test_wire_oc_frames.py python
296 lines 11.3 KB
Raw
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 132 days ago
1 """TDD — Phase 14B: OC (Object Chunk) frame protocol.
2
3 Large objects (> OC_CHUNK_SIZE) are split into OC frames so they can be
4 streamed through MWP without hitting proxy body limits.
5
6 Rules encoded here:
7
8 P14B-0 OC_CHUNK_SIZE exported from muse.core.transport, equals 290 * 1024.
9
10 P14B-1 Object of exactly OC_CHUNK_SIZE bytes → 1 plain O-frame (no chunking).
11
12 P14B-2 Object of OC_CHUNK_SIZE + 1 bytes → 2 OC-frames; each ≤ OC_CHUNK_SIZE.
13
14 P14B-3 Object of 3 × OC_CHUNK_SIZE bytes → 3 OC-frames; bytes sum to original.
15
16 P14B-4 chunk_index=0 has `encoding`, `path`, `sz`; subsequent chunks do not.
17
18 P14B-5 `split_object_into_oc_frames` is exported from muse.core.transport and
19 returns a list of frame dicts (not ObjectPayload — raw dicts for wire).
20
21 P14B-6 All returned frames have t="OC", object_id, chunk_index, total_chunks,
22 content. Last frame has chunk_index == total_chunks - 1.
23 """
24 from __future__ import annotations
25
26 import math
27 from typing import Any
28
29 import pytest
30
31
32 # ---------------------------------------------------------------------------
33 # P14B-0 — OC_CHUNK_SIZE exported from muse.core.transport
34 # ---------------------------------------------------------------------------
35
36 class TestP14B0ChunkSizeExported:
37 def test_oc_chunk_size_is_positive_int(self) -> None:
38 from muse.core.transport import OC_CHUNK_SIZE # type: ignore[attr-defined]
39 assert isinstance(OC_CHUNK_SIZE, int)
40 assert OC_CHUNK_SIZE > 0
41
42 def test_oc_chunk_size_equals_290kb(self) -> None:
43 from muse.core.transport import OC_CHUNK_SIZE # type: ignore[attr-defined]
44 assert OC_CHUNK_SIZE == 290 * 1024
45
46
47 # ---------------------------------------------------------------------------
48 # P14B-1 — Object exactly OC_CHUNK_SIZE → 1 plain O-frame (no chunking)
49 # ---------------------------------------------------------------------------
50
51 class TestP14B1ExactSizeNoChunking:
52 def test_object_at_chunk_size_is_single_o_frame(self) -> None:
53 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
54
55 obj = {
56 "object_id": "sha256:" + "b" * 64,
57 "content": bytes(OC_CHUNK_SIZE),
58 "encoding": "raw",
59 "path": "big.bin",
60 }
61 frames = split_object_into_oc_frames(obj)
62 # Exactly one frame, and it's a regular O-frame
63 assert len(frames) == 1
64 assert frames[0]["t"] == "O"
65 assert frames[0]["content"] == obj["content"]
66
67 def test_object_below_chunk_size_is_single_o_frame(self) -> None:
68 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
69
70 obj = {
71 "object_id": "sha256:" + "c" * 64,
72 "content": bytes(OC_CHUNK_SIZE - 1),
73 "encoding": "raw",
74 "path": "medium.bin",
75 }
76 frames = split_object_into_oc_frames(obj)
77 assert len(frames) == 1
78 assert frames[0]["t"] == "O"
79
80
81 # ---------------------------------------------------------------------------
82 # P14B-2 — Object of OC_CHUNK_SIZE + 1 bytes → 2 OC-frames
83 # ---------------------------------------------------------------------------
84
85 class TestP14B2TwoChunks:
86 def _get_frames(self, size: int) -> list[dict]:
87 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
88 pattern = bytes(range(256))
89 content = (pattern * ((size // 256) + 1))[:size]
90 obj = {
91 "object_id": "sha256:" + "d" * 64,
92 "content": content,
93 "encoding": "raw",
94 "path": "large.bin",
95 }
96 return split_object_into_oc_frames(obj)
97
98 def test_one_byte_over_chunk_size_produces_two_frames(self) -> None:
99 from muse.core.transport import OC_CHUNK_SIZE # type: ignore[attr-defined]
100 frames = self._get_frames(OC_CHUNK_SIZE + 1)
101 assert len(frames) == 2
102
103 def test_all_frames_are_oc_type(self) -> None:
104 from muse.core.transport import OC_CHUNK_SIZE # type: ignore[attr-defined]
105 frames = self._get_frames(OC_CHUNK_SIZE + 1)
106 for f in frames:
107 assert f["t"] == "OC"
108
109 def test_each_frame_content_le_chunk_size(self) -> None:
110 from muse.core.transport import OC_CHUNK_SIZE # type: ignore[attr-defined]
111 frames = self._get_frames(OC_CHUNK_SIZE + 1)
112 for f in frames:
113 assert len(f["content"]) <= OC_CHUNK_SIZE
114
115 def test_frame_content_sums_to_original(self) -> None:
116 from muse.core.transport import OC_CHUNK_SIZE # type: ignore[attr-defined]
117 size = OC_CHUNK_SIZE + 1
118 frames = self._get_frames(size)
119 reassembled = b"".join(f["content"] for f in frames)
120 assert len(reassembled) == size
121
122
123 # ---------------------------------------------------------------------------
124 # P14B-3 — Object of 3 × OC_CHUNK_SIZE bytes → 3 OC-frames
125 # ---------------------------------------------------------------------------
126
127 class TestP14B3ThreeChunks:
128 def test_three_chunk_size_object_produces_three_frames(self) -> None:
129 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
130
131 size = OC_CHUNK_SIZE * 3
132 content = bytes([i % 256 for i in range(size)])
133 obj = {
134 "object_id": "sha256:" + "e" * 64,
135 "content": content,
136 "encoding": "raw",
137 "path": "triple.bin",
138 }
139 frames = split_object_into_oc_frames(obj)
140 assert len(frames) == 3
141
142 def test_three_chunks_reassemble_correctly(self) -> None:
143 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
144
145 size = OC_CHUNK_SIZE * 3
146 content = bytes([i % 256 for i in range(size)])
147 obj = {
148 "object_id": "sha256:" + "f" * 64,
149 "content": content,
150 "encoding": "raw",
151 "path": "triple.bin",
152 }
153 frames = split_object_into_oc_frames(obj)
154 reassembled = b"".join(f["content"] for f in frames)
155 assert reassembled == content
156
157 def test_total_chunks_field_is_correct(self) -> None:
158 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
159
160 size = OC_CHUNK_SIZE * 3
161 content = bytes(size)
162 obj = {
163 "object_id": "sha256:" + "e" * 64,
164 "content": content,
165 "encoding": "raw",
166 "path": "triple.bin",
167 }
168 frames = split_object_into_oc_frames(obj)
169 for f in frames:
170 assert f["total_chunks"] == 3
171
172 def test_chunk_indices_are_sequential(self) -> None:
173 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
174
175 size = OC_CHUNK_SIZE * 3
176 content = bytes(size)
177 obj = {
178 "object_id": "sha256:" + "e" * 64,
179 "content": content,
180 "encoding": "raw",
181 "path": "triple.bin",
182 }
183 frames = split_object_into_oc_frames(obj)
184 indices = [f["chunk_index"] for f in frames]
185 assert indices == [0, 1, 2]
186
187
188 # ---------------------------------------------------------------------------
189 # P14B-4 — Only chunk_index=0 carries encoding, path, sz
190 # ---------------------------------------------------------------------------
191
192 class TestP14B4MetadataOnFirstChunkOnly:
193 def _frames_for_large_object(self) -> list[dict]:
194 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
195 size = OC_CHUNK_SIZE * 2 + 1
196 content = bytes(size)
197 obj = {
198 "object_id": "sha256:" + "a" * 64,
199 "content": content,
200 "encoding": "raw",
201 "path": "large.bin",
202 }
203 return split_object_into_oc_frames(obj)
204
205 def test_first_chunk_has_encoding(self) -> None:
206 frames = self._frames_for_large_object()
207 assert "encoding" in frames[0]
208
209 def test_first_chunk_has_path(self) -> None:
210 frames = self._frames_for_large_object()
211 assert "path" in frames[0]
212
213 def test_first_chunk_has_sz(self) -> None:
214 frames = self._frames_for_large_object()
215 assert "sz" in frames[0]
216 from muse.core.transport import OC_CHUNK_SIZE # type: ignore[attr-defined]
217 assert frames[0]["sz"] == OC_CHUNK_SIZE * 2 + 1
218
219 def test_subsequent_chunks_have_no_encoding(self) -> None:
220 frames = self._frames_for_large_object()
221 for f in frames[1:]:
222 assert "encoding" not in f
223
224 def test_subsequent_chunks_have_no_path(self) -> None:
225 frames = self._frames_for_large_object()
226 for f in frames[1:]:
227 assert "path" not in f
228
229 def test_subsequent_chunks_have_no_sz(self) -> None:
230 frames = self._frames_for_large_object()
231 for f in frames[1:]:
232 assert "sz" not in f
233
234
235 # ---------------------------------------------------------------------------
236 # P14B-5 — split_object_into_oc_frames exported, returns list of dicts
237 # ---------------------------------------------------------------------------
238
239 class TestP14B5FunctionExported:
240 def test_function_is_callable(self) -> None:
241 from muse.core.transport import split_object_into_oc_frames # type: ignore[attr-defined]
242 assert callable(split_object_into_oc_frames)
243
244 def test_returns_list_of_dicts(self) -> None:
245 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
246 obj = {
247 "object_id": "sha256:" + "a" * 64,
248 "content": bytes(10),
249 "encoding": "raw",
250 "path": "tiny.bin",
251 }
252 result = split_object_into_oc_frames(obj)
253 assert isinstance(result, list)
254 for item in result:
255 assert isinstance(item, dict)
256
257
258 # ---------------------------------------------------------------------------
259 # P14B-6 — All OC frames have required fields; last frame has correct index
260 # ---------------------------------------------------------------------------
261
262 class TestP14B6FrameFields:
263 def test_all_oc_frames_have_required_fields(self) -> None:
264 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
265
266 size = OC_CHUNK_SIZE * 2 + 512
267 content = bytes(size)
268 obj = {
269 "object_id": "sha256:" + "b" * 64,
270 "content": content,
271 "encoding": "raw",
272 "path": "multi.bin",
273 }
274 frames = split_object_into_oc_frames(obj)
275 for f in frames:
276 assert "t" in f
277 assert "object_id" in f
278 assert "chunk_index" in f
279 assert "total_chunks" in f
280 assert "content" in f
281 assert f["object_id"] == obj["object_id"]
282
283 def test_last_frame_chunk_index_equals_total_minus_one(self) -> None:
284 from muse.core.transport import OC_CHUNK_SIZE, split_object_into_oc_frames # type: ignore[attr-defined]
285
286 size = OC_CHUNK_SIZE * 4
287 content = bytes(size)
288 obj = {
289 "object_id": "sha256:" + "c" * 64,
290 "content": content,
291 "encoding": "raw",
292 "path": "quad.bin",
293 }
294 frames = split_object_into_oc_frames(obj)
295 last = frames[-1]
296 assert last["chunk_index"] == last["total_chunks"] - 1
File History 1 commit
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 132 days ago