Skip to content

Commit 872055e

Browse files
Pin golden bytes for Heartbeat, Interrupt, Files responses
test_codec.py already exercises round-trip encode/decode for HeartbeatRequest, InterruptRequest, and FilesResponse, but round-trip tests would not catch a symmetric bug where both encoder and decoder drift from the wire-protocol spec in the same direction. test_golden_bytes.py is the spec-pinned fence — hex literals derived from the protocol rules, independent of the Python encoder. Extend it to cover these three message types so future refactors of the header, text padding, or body layout cannot silently change what we send on the wire while still round-tripping. The FilesResponse case exercises the 8-byte content-alignment rule that gateway.c asserts server-side, catching any future accidental drift toward per-file padding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7743347 commit 872055e

1 file changed

Lines changed: 63 additions & 0 deletions

File tree

tests/test_golden_bytes.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
ExecRequest,
2525
ExecSqlRequest,
2626
FailureResponse,
27+
FilesResponse,
2728
FinalizeRequest,
29+
HeartbeatRequest,
30+
InterruptRequest,
2831
LeaderRequest,
2932
LeaderResponse,
3033
MetadataResponse,
@@ -118,6 +121,36 @@ def test_finalize_request(self) -> None:
118121
assert msg.db_id == 1
119122
assert msg.stmt_id == 2
120123

124+
def test_heartbeat_request(self) -> None:
125+
"""HeartbeatRequest(timestamp=1_700_000_000): type=2, body=uint64.
126+
127+
The C server currently does not dispatch HEARTBEAT, but the wire
128+
layout is still shipped as part of the public message surface;
129+
pin it here so an encoder refactor cannot drift the byte shape
130+
symmetrically with the decoder.
131+
"""
132+
ts = 1_700_000_000
133+
expected = _header(1, 2) + _u64(ts)
134+
assert encode_message(HeartbeatRequest(timestamp=ts)) == expected
135+
136+
msg = decode_message(expected, is_request=True)
137+
assert isinstance(msg, HeartbeatRequest)
138+
assert msg.timestamp == ts
139+
140+
def test_interrupt_request(self) -> None:
141+
"""InterruptRequest(db_id=0x1234567890ABCDEF): type=10.
142+
143+
Body: uint64(db_id). Single-field message, easy to misencode
144+
LE-vs-BE on a refactor; golden pin catches it immediately.
145+
"""
146+
db_id = 0x1234567890ABCDEF
147+
expected = _header(1, 10) + _u64(db_id)
148+
assert encode_message(InterruptRequest(db_id=db_id)) == expected
149+
150+
msg = decode_message(expected, is_request=True)
151+
assert isinstance(msg, InterruptRequest)
152+
assert msg.db_id == db_id
153+
121154
def test_exec_request_with_params(self) -> None:
122155
"""ExecRequest(db_id=1, stmt_id=2, params=[42, "hello"]): type=5, schema=0.
123156
@@ -267,6 +300,36 @@ def test_rows_response_part_marker(self) -> None:
267300
# Last 8 bytes should be the PART marker
268301
assert body[-8:] == part_marker
269302

303+
def test_files_response(self) -> None:
304+
"""FilesResponse with two files: type=9.
305+
306+
Body layout: uint64(count), then for each file
307+
text(name) — null-terminated, padded to 8-byte boundary
308+
uint64(size) — must be 8-byte aligned (no per-file padding)
309+
raw content — ``size`` bytes, 8-byte aligned
310+
311+
File 1: name="db" → b"db\\0\\0\\0\\0\\0\\0" (8 bytes), 8 bytes of content.
312+
File 2: name="main.db" → b"main.db\\0" (exact word), 16 bytes of content.
313+
314+
Total body = 8 (count) + 8+8+8 (f1) + 8+8+16 (f2) = 64 bytes = 8 words.
315+
"""
316+
count = _u64(2)
317+
f1_name = _text("db") # 8 bytes
318+
f1_size = _u64(8)
319+
f1_content = b"pageonep" # exactly 8 bytes
320+
f2_name = _text("main.db") # 8 bytes
321+
f2_size = _u64(16)
322+
f2_content = b"pageone_pagetwo_" # exactly 16 bytes
323+
expected_body = count + f1_name + f1_size + f1_content + f2_name + f2_size + f2_content
324+
expected = _header(len(expected_body) // 8, 9) + expected_body
325+
326+
msg = FilesResponse(files={"db": f1_content, "main.db": f2_content})
327+
assert encode_message(msg) == expected
328+
329+
decoded = decode_message(expected, is_request=False)
330+
assert isinstance(decoded, FilesResponse)
331+
assert decoded.files == {"db": f1_content, "main.db": f2_content}
332+
270333

271334
class TestGoldenHandshake:
272335
"""Verify handshake encoding."""

0 commit comments

Comments
 (0)