gabriel / muse public
test_mpack_compression.py python
199 lines 7.5 KB
Raw
sha256:81ae324db5ad375fbfe4834c6fcb378312cafad3cc92dec5d3e5c427306621a2 fix: remove commit_exists filter from have anchors — server… Sonnet 4.6 patch 22 days ago
1 """Tests for MPack compression — zstd support and zlib fallback.
2
3 Coverage tiers
4 --------------
5 - ZSTD_AVAILABLE: boolean flag reflects package presence
6 - compress_zstd / decompress_zstd: round-trip fidelity
7 - compress_zstd: fallback to zlib when zstd absent (tested via monkeypatching)
8 - choose_compression: returns "zstd" when available, "zlib" otherwise
9 - Compression ratio: zstd ≥ zlib on source code (when zstd available)
10 - Edge cases: empty bytes, single byte, 1MB payload
11 - Error handling: corrupt data raises on decompress
12 """
13 from __future__ import annotations
14
15 import zlib
16
17 import pytest
18
19
20 # ---------------------------------------------------------------------------
21 # ZSTD_AVAILABLE flag
22 # ---------------------------------------------------------------------------
23
24
25 class TestZstdAvailableFlag:
26 def test_zstd_available_is_bool(self) -> None:
27 from muse.core.compression import ZSTD_AVAILABLE
28 assert isinstance(ZSTD_AVAILABLE, bool)
29
30 def test_zstd_available_reflects_import(self) -> None:
31 from muse.core.compression import ZSTD_AVAILABLE
32 try:
33 import zstandard # noqa: F401
34 expected = True
35 except ImportError:
36 expected = False
37 assert ZSTD_AVAILABLE == expected
38
39
40 # ---------------------------------------------------------------------------
41 # compress_zstd / decompress_zstd — round-trip
42 # ---------------------------------------------------------------------------
43
44
45 class TestZstdRoundTrip:
46 def test_empty_bytes(self) -> None:
47 from muse.core.compression import compress_zstd, decompress_zstd
48 assert decompress_zstd(compress_zstd(b"")) == b""
49
50 def test_single_byte(self) -> None:
51 from muse.core.compression import compress_zstd, decompress_zstd
52 assert decompress_zstd(compress_zstd(b"\x00")) == b"\x00"
53
54 def test_source_code(self) -> None:
55 from muse.core.compression import compress_zstd, decompress_zstd
56 data = b"def hello():\n return 'world'\n" * 100
57 assert decompress_zstd(compress_zstd(data)) == data
58
59 def test_binary_data(self) -> None:
60 from muse.core.compression import compress_zstd, decompress_zstd
61 data = bytes(range(256)) * 500
62 assert decompress_zstd(compress_zstd(data)) == data
63
64 def test_1mb_payload(self) -> None:
65 from muse.core.compression import compress_zstd, decompress_zstd
66 data = b"x" * (1024 * 1024)
67 assert decompress_zstd(compress_zstd(data)) == data
68
69 def test_compress_returns_bytes(self) -> None:
70 from muse.core.compression import compress_zstd
71 result = compress_zstd(b"hello")
72 assert isinstance(result, bytes)
73
74 def test_decompress_returns_bytes(self) -> None:
75 from muse.core.compression import compress_zstd, decompress_zstd
76 result = decompress_zstd(compress_zstd(b"hello"))
77 assert isinstance(result, bytes)
78
79
80 # ---------------------------------------------------------------------------
81 # choose_compression
82 # ---------------------------------------------------------------------------
83
84
85 class TestChooseCompression:
86 def test_returns_string(self) -> None:
87 from muse.core.compression import choose_compression
88 result = choose_compression()
89 assert isinstance(result, str)
90
91 def test_returns_valid_encoding(self) -> None:
92 from muse.core.compression import choose_compression
93 result = choose_compression()
94 assert result in ("zstd", "zlib")
95
96 def test_matches_zstd_available(self) -> None:
97 from muse.core.compression import choose_compression, ZSTD_AVAILABLE
98 result = choose_compression()
99 if ZSTD_AVAILABLE:
100 assert result == "zstd"
101 else:
102 assert result == "zlib"
103
104
105 # ---------------------------------------------------------------------------
106 # compress_and_encode / decompress_frame — unified interface
107 # ---------------------------------------------------------------------------
108
109
110 class TestCompressAndEncode:
111 def test_compress_and_encode_returns_bytes_and_enc(self) -> None:
112 from muse.core.compression import compress_and_encode
113 data = b"hello world " * 50
114 compressed, enc = compress_and_encode(data)
115 assert isinstance(compressed, bytes)
116 assert enc in ("zstd", "zlib")
117
118 def test_compress_and_encode_round_trip(self) -> None:
119 from muse.core.compression import compress_and_encode, decompress_frame
120 data = b"round trip test " * 100
121 compressed, enc = compress_and_encode(data)
122 recovered = decompress_frame(compressed, enc)
123 assert recovered == data
124
125 def test_decompress_frame_zlib(self) -> None:
126 from muse.core.compression import decompress_frame
127 data = b"hello"
128 compressed = zlib.compress(data)
129 assert decompress_frame(compressed, "zlib") == data
130
131 def test_decompress_frame_raw(self) -> None:
132 from muse.core.compression import decompress_frame
133 data = b"raw bytes"
134 assert decompress_frame(data, "raw") == data
135
136 def test_decompress_frame_unknown_enc_raises(self) -> None:
137 from muse.core.compression import decompress_frame
138 with pytest.raises((ValueError, Exception)):
139 decompress_frame(b"data", "lz4")
140
141
142 # ---------------------------------------------------------------------------
143 # Compression ratio (zstd ≥ zlib on source code, when zstd available)
144 # ---------------------------------------------------------------------------
145
146
147 class TestCompressionRatio:
148 def test_zstd_at_least_as_good_as_zlib_on_source(self) -> None:
149 from muse.core.compression import ZSTD_AVAILABLE, compress_zstd, compress_zlib
150 if not ZSTD_AVAILABLE:
151 pytest.skip("zstd not available")
152 data = b"def foo(x):\n return x + 1\n" * 200
153 zstd_size = len(compress_zstd(data))
154 zlib_size = len(compress_zlib(data))
155 # zstd should be at least as good — not necessarily better on every payload
156 assert zstd_size <= zlib_size * 1.1, (
157 f"zstd ({zstd_size}B) more than 10% larger than zlib ({zlib_size}B)"
158 )
159
160 def test_zstd_faster_than_zlib_on_large_payload(self) -> None:
161 """zstd level 3 should be faster than zlib level 1 on large data."""
162 import time
163 from muse.core.compression import ZSTD_AVAILABLE, compress_zstd, compress_zlib
164 if not ZSTD_AVAILABLE:
165 pytest.skip("zstd not available")
166 data = b"source code line\n" * 100_000 # ~1.7 MB
167 t0 = time.monotonic()
168 for _ in range(5):
169 compress_zlib(data)
170 zlib_time = time.monotonic() - t0
171
172 t0 = time.monotonic()
173 for _ in range(5):
174 compress_zstd(data)
175 zstd_time = time.monotonic() - t0
176
177 # zstd should be meaningfully faster on large repetitive payloads
178 assert zstd_time < zlib_time * 2.0, (
179 f"zstd ({zstd_time:.3f}s) not faster than 2× zlib ({zlib_time:.3f}s)"
180 )
181
182
183 # ---------------------------------------------------------------------------
184 # Error handling
185 # ---------------------------------------------------------------------------
186
187
188 class TestDecompressErrors:
189 def test_corrupt_zlib_raises(self) -> None:
190 from muse.core.compression import decompress_zlib
191 with pytest.raises(zlib.error):
192 decompress_zlib(b"not valid zlib")
193
194 def test_corrupt_zstd_raises(self) -> None:
195 from muse.core.compression import ZSTD_AVAILABLE, decompress_zstd
196 if not ZSTD_AVAILABLE:
197 pytest.skip("zstd not available")
198 with pytest.raises(Exception):
199 decompress_zstd(b"not valid zstd")
File History 4 commits
sha256:81ae324db5ad375fbfe4834c6fcb378312cafad3cc92dec5d3e5c427306621a2 fix: remove commit_exists filter from have anchors — server… Sonnet 4.6 patch 22 days ago
sha256:36c3cb3e76619d4c30a6d9bf81b5ec4ff148e30dcfed913e3114ca7b43b81c7e fix: rename objects→blobs in push client and all stale test… Sonnet 4.6 patch 23 days ago
sha256:c06a9b9b9fee26c68ea725b44d54b2c0a171301ce9de746d5b656617b4463a9a fix: repair four test failures from post-migration audit Sonnet 4.6 patch 30 days ago
sha256:1900655993c83c4107067375548a7be823e471d2515830842f1a12cba4bd3cdf fix: unified object store migration — idempotent writes, JS… Sonnet 4.6 minor 30 days ago