test_network_compression.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. # -*- coding: utf-8 -*-
  2. """
  3. Tests für Network Compression.
  4. """
  5. import pytest
  6. from trixy_core.network.compression import (
  7. Compressor,
  8. CompressionLevel,
  9. CompressionStats,
  10. ZlibCompressor,
  11. CompressionRegistry,
  12. get_default_registry,
  13. get_compressor,
  14. )
  15. from trixy_core.network.compression.compressor import (
  16. CompressionError,
  17. DecompressionError,
  18. )
  19. from trixy_core.network.compression.zlib import GzipCompressor
  20. class TestCompressionLevel:
  21. """Tests für CompressionLevel."""
  22. def test_level_values(self):
  23. """Testet Level-Werte."""
  24. assert CompressionLevel.NONE == 0
  25. assert CompressionLevel.FASTEST == 1
  26. assert CompressionLevel.DEFAULT == 6
  27. assert CompressionLevel.BEST == 9
  28. def test_level_ordering(self):
  29. """Testet Level-Reihenfolge."""
  30. assert CompressionLevel.FASTEST < CompressionLevel.DEFAULT
  31. assert CompressionLevel.DEFAULT < CompressionLevel.BEST
  32. class TestCompressionStats:
  33. """Tests für CompressionStats."""
  34. def test_initial_stats(self):
  35. """Testet initiale Statistiken."""
  36. stats = CompressionStats()
  37. assert stats.total_compressed == 0
  38. assert stats.total_decompressed == 0
  39. assert stats.bytes_in == 0
  40. assert stats.bytes_out == 0
  41. def test_update_compression(self):
  42. """Testet Komprimierungs-Update."""
  43. stats = CompressionStats()
  44. stats.update_compression(1000, 100, 5.0)
  45. assert stats.total_compressed == 1
  46. assert stats.bytes_in == 1000
  47. assert stats.bytes_out == 100
  48. assert stats.compression_ratio == 0.1
  49. assert stats.total_time_ms == 5.0
  50. def test_update_decompression(self):
  51. """Testet Dekomprimierungs-Update."""
  52. stats = CompressionStats()
  53. stats.update_decompression(100, 1000, 3.0)
  54. assert stats.total_decompressed == 1
  55. assert stats.total_time_ms == 3.0
  56. def test_to_dict(self):
  57. """Testet Dictionary-Konvertierung."""
  58. stats = CompressionStats()
  59. stats.update_compression(1000, 100, 5.0)
  60. d = stats.to_dict()
  61. assert "total_compressed" in d
  62. assert "compression_ratio" in d
  63. assert "space_saved_percent" in d
  64. assert d["space_saved_percent"] == 90.0
  65. class TestZlibCompressor:
  66. """Tests für ZlibCompressor."""
  67. @pytest.fixture
  68. def compressor(self):
  69. """Erstellt ZlibCompressor."""
  70. return ZlibCompressor(level=CompressionLevel.DEFAULT)
  71. @pytest.fixture
  72. def test_data(self):
  73. """Test-Daten."""
  74. return b"Hello World! " * 100
  75. def test_compression_basic(self, compressor, test_data):
  76. """Testet grundlegende Komprimierung."""
  77. compressed = compressor.compress(test_data)
  78. assert len(compressed) < len(test_data)
  79. assert compressed != test_data
  80. def test_decompression_basic(self, compressor, test_data):
  81. """Testet grundlegende Dekomprimierung."""
  82. compressed = compressor.compress(test_data)
  83. decompressed = compressor.decompress(compressed)
  84. assert decompressed == test_data
  85. def test_compression_empty_data(self, compressor):
  86. """Testet Komprimierung leerer Daten."""
  87. result = compressor.compress(b"")
  88. assert result == b""
  89. def test_decompression_empty_data(self, compressor):
  90. """Testet Dekomprimierung leerer Daten."""
  91. result = compressor.decompress(b"")
  92. assert result == b""
  93. def test_compression_levels(self, test_data):
  94. """Testet verschiedene Komprimierungsstufen."""
  95. fast = ZlibCompressor(level=CompressionLevel.FASTEST)
  96. best = ZlibCompressor(level=CompressionLevel.BEST)
  97. fast_compressed = fast.compress(test_data)
  98. best_compressed = best.compress(test_data)
  99. # BEST sollte kleinere Ausgabe produzieren
  100. assert len(best_compressed) <= len(fast_compressed)
  101. # Beide sollten korrekt dekomprimieren
  102. assert fast.decompress(fast_compressed) == test_data
  103. assert best.decompress(best_compressed) == test_data
  104. def test_statistics_tracking(self, compressor, test_data):
  105. """Testet Statistik-Tracking."""
  106. compressor.compress(test_data)
  107. compressor.compress(test_data)
  108. assert compressor.stats.total_compressed == 2
  109. assert compressor.stats.bytes_in == len(test_data) * 2
  110. def test_compress_with_header(self, compressor, test_data):
  111. """Testet Komprimierung mit Header."""
  112. compressed = compressor.compress_with_header(test_data)
  113. # Header: 4 Bytes Größe
  114. assert len(compressed) > 4
  115. def test_decompress_with_header(self, compressor, test_data):
  116. """Testet Dekomprimierung mit Header."""
  117. compressed = compressor.compress_with_header(test_data)
  118. decompressed = compressor.decompress_with_header(compressed)
  119. assert decompressed == test_data
  120. def test_should_compress(self, compressor):
  121. """Testet should_compress."""
  122. small_data = b"Hi"
  123. large_data = b"Hello World! " * 100
  124. assert not compressor.should_compress(small_data)
  125. assert compressor.should_compress(large_data)
  126. def test_compress_if_beneficial(self, compressor):
  127. """Testet compress_if_beneficial."""
  128. # Komprimierbare Daten
  129. large_data = b"Hello World! " * 100
  130. result, was_compressed = compressor.compress_if_beneficial(large_data)
  131. assert was_compressed
  132. assert len(result) < len(large_data)
  133. # Zu kleine Daten
  134. small_data = b"Hi"
  135. result, was_compressed = compressor.compress_if_beneficial(small_data)
  136. assert not was_compressed
  137. assert result == small_data
  138. def test_invalid_decompression(self, compressor):
  139. """Testet ungültige Dekomprimierung."""
  140. with pytest.raises(DecompressionError):
  141. compressor.decompress(b"invalid data that is not compressed")
  142. def test_properties(self, compressor):
  143. """Testet Compressor-Properties."""
  144. assert compressor.name == "zlib"
  145. assert compressor.content_type == "application/zlib"
  146. assert compressor.min_size > 0
  147. def test_reset_stats(self, compressor, test_data):
  148. """Testet Stats-Reset."""
  149. compressor.compress(test_data)
  150. assert compressor.stats.total_compressed == 1
  151. compressor.reset_stats()
  152. assert compressor.stats.total_compressed == 0
  153. class TestGzipCompressor:
  154. """Tests für GzipCompressor."""
  155. @pytest.fixture
  156. def compressor(self):
  157. """Erstellt GzipCompressor."""
  158. return GzipCompressor(level=CompressionLevel.DEFAULT)
  159. @pytest.fixture
  160. def test_data(self):
  161. """Test-Daten."""
  162. return b"Test data for gzip compression " * 50
  163. def test_compression_basic(self, compressor, test_data):
  164. """Testet grundlegende Gzip-Komprimierung."""
  165. compressed = compressor.compress(test_data)
  166. assert len(compressed) < len(test_data)
  167. def test_decompression_basic(self, compressor, test_data):
  168. """Testet grundlegende Gzip-Dekomprimierung."""
  169. compressed = compressor.compress(test_data)
  170. decompressed = compressor.decompress(compressed)
  171. assert decompressed == test_data
  172. def test_properties(self, compressor):
  173. """Testet Gzip-Properties."""
  174. assert compressor.name == "gzip"
  175. assert compressor.content_type == "application/gzip"
  176. class TestCompressionRegistry:
  177. """Tests für CompressionRegistry."""
  178. @pytest.fixture
  179. def registry(self):
  180. """Erstellt neue Registry."""
  181. return CompressionRegistry()
  182. def test_register_compressor(self, registry):
  183. """Testet Compressor-Registrierung."""
  184. registry.register("test", ZlibCompressor, "application/test")
  185. assert "test" in registry
  186. assert registry.is_available("test")
  187. def test_get_compressor(self, registry):
  188. """Testet Compressor-Abruf."""
  189. registry.register("test", ZlibCompressor)
  190. compressor = registry.get("test")
  191. assert compressor is not None
  192. assert isinstance(compressor, ZlibCompressor)
  193. def test_get_nonexistent(self, registry):
  194. """Testet Abruf nicht existierender Compressor."""
  195. result = registry.get("nonexistent")
  196. assert result is None
  197. def test_get_by_content_type(self, registry):
  198. """Testet Abruf nach Content-Type."""
  199. registry.register("test", ZlibCompressor, "application/test")
  200. compressor = registry.get_by_content_type("application/test")
  201. assert compressor is not None
  202. def test_unregister(self, registry):
  203. """Testet Compressor-Entfernung."""
  204. registry.register("test", ZlibCompressor)
  205. assert registry.unregister("test")
  206. assert "test" not in registry
  207. def test_list_available(self, registry):
  208. """Testet Auflistung."""
  209. registry.register("comp1", ZlibCompressor)
  210. registry.register("comp2", ZlibCompressor)
  211. available = registry.list_available()
  212. assert "comp1" in available
  213. assert "comp2" in available
  214. class TestDefaultRegistry:
  215. """Tests für Default-Registry."""
  216. def test_get_default_registry(self):
  217. """Testet Default-Registry."""
  218. registry = get_default_registry()
  219. assert registry is not None
  220. assert len(registry) >= 2 # zlib und gzip
  221. def test_default_compressors(self):
  222. """Testet Standard-Compressors."""
  223. registry = get_default_registry()
  224. assert "zlib" in registry
  225. assert "gzip" in registry
  226. def test_get_compressor_convenience(self):
  227. """Testet get_compressor Convenience-Funktion."""
  228. compressor = get_compressor("zlib")
  229. assert compressor is not None
  230. assert isinstance(compressor, ZlibCompressor)
  231. def test_get_compressor_with_level(self):
  232. """Testet get_compressor mit Level."""
  233. compressor = get_compressor("zlib", CompressionLevel.BEST)
  234. assert compressor is not None
  235. assert compressor.level == CompressionLevel.BEST
  236. class TestCompressionRoundTrip:
  237. """Integrationstests für Komprimierung."""
  238. @pytest.mark.parametrize("size", [100, 1000, 10000, 100000])
  239. def test_various_sizes(self, size):
  240. """Testet verschiedene Datengrößen."""
  241. compressor = ZlibCompressor()
  242. data = b"x" * size
  243. compressed = compressor.compress(data)
  244. decompressed = compressor.decompress(compressed)
  245. assert decompressed == data
  246. @pytest.mark.parametrize("pattern", [
  247. b"AAAAAAAAAA" * 100, # Repetitiv
  248. bytes(range(256)) * 10, # Sequentiell
  249. b"\x00" * 1000, # Nullen
  250. ])
  251. def test_various_patterns(self, pattern):
  252. """Testet verschiedene Datenmuster."""
  253. compressor = ZlibCompressor()
  254. compressed = compressor.compress(pattern)
  255. decompressed = compressor.decompress(compressed)
  256. assert decompressed == pattern
  257. def test_binary_data(self):
  258. """Testet binäre Daten."""
  259. import os
  260. compressor = ZlibCompressor()
  261. data = os.urandom(10000) # Zufällige Bytes
  262. compressed = compressor.compress(data)
  263. decompressed = compressor.decompress(compressed)
  264. assert decompressed == data