// Reference: golang/nats-server/server/route.go — S2/Snappy compression for routes // Tests for RouteCompressionCodec: compression, decompression, negotiation, detection. using System.Text; using NATS.Server.Routes; namespace NATS.Server.Clustering.Tests.Routes; /// /// Tests for route S2/Snappy compression codec, matching Go's route compression /// behavior using IronSnappy. /// public class RouteS2CompressionTests { [Fact] public void Compress_Fast_ProducesValidOutput() { var data = Encoding.UTF8.GetBytes("NATS route compression test payload"); var compressed = RouteCompressionCodec.Compress(data, RouteCompressionLevel.Fast); compressed.ShouldNotBeNull(); compressed.Length.ShouldBeGreaterThan(0); // Compressed output should be decompressible var decompressed = RouteCompressionCodec.Decompress(compressed); decompressed.ShouldBe(data); } [Fact] public void Compress_Decompress_RoundTrips() { var original = Encoding.UTF8.GetBytes("Hello NATS! This is a test of round-trip compression."); foreach (var level in new[] { RouteCompressionLevel.Fast, RouteCompressionLevel.Better, RouteCompressionLevel.Best }) { var compressed = RouteCompressionCodec.Compress(original, level); var restored = RouteCompressionCodec.Decompress(compressed); restored.ShouldBe(original, $"Round-trip failed for level {level}"); } } [Fact] public void Compress_EmptyData_ReturnsEmpty() { var result = RouteCompressionCodec.Compress(ReadOnlySpan.Empty, RouteCompressionLevel.Fast); result.ShouldBeEmpty(); } [Fact] public void Compress_Off_ReturnsOriginal() { var data = Encoding.UTF8.GetBytes("uncompressed payload"); var result = RouteCompressionCodec.Compress(data, RouteCompressionLevel.Off); result.ShouldBe(data); } [Fact] public void Decompress_CorruptedData_Throws() { var garbage = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02, 0x03, 0x04 }; Should.Throw(() => RouteCompressionCodec.Decompress(garbage)); } [Fact] public void NegotiateCompression_BothOff_ReturnsOff() { var result = RouteCompressionCodec.NegotiateCompression("off", "off"); result.ShouldBe(RouteCompressionLevel.Off); } [Fact] public void NegotiateCompression_OneFast_ReturnsFast() { // When both are fast, result is fast var result = RouteCompressionCodec.NegotiateCompression("fast", "fast"); result.ShouldBe(RouteCompressionLevel.Fast); // When one is off, result is off (off wins) var result2 = RouteCompressionCodec.NegotiateCompression("fast", "off"); result2.ShouldBe(RouteCompressionLevel.Off); } [Fact] public void NegotiateCompression_MismatchLevels_ReturnsMinimum() { // fast (1) vs best (3) => fast (minimum) var result = RouteCompressionCodec.NegotiateCompression("fast", "best"); result.ShouldBe(RouteCompressionLevel.Fast); // better (2) vs best (3) => better (minimum) var result2 = RouteCompressionCodec.NegotiateCompression("better", "best"); result2.ShouldBe(RouteCompressionLevel.Better); // fast (1) vs better (2) => fast (minimum) var result3 = RouteCompressionCodec.NegotiateCompression("fast", "better"); result3.ShouldBe(RouteCompressionLevel.Fast); } [Fact] public void IsCompressed_ValidSnappy_ReturnsTrue() { var data = Encoding.UTF8.GetBytes("This is test data for Snappy compression detection"); var compressed = RouteCompressionCodec.Compress(data, RouteCompressionLevel.Fast); RouteCompressionCodec.IsCompressed(compressed).ShouldBeTrue(); } [Fact] public void IsCompressed_PlainText_ReturnsFalse() { var plainText = Encoding.UTF8.GetBytes("PUB test.subject 5\r\nhello\r\n"); RouteCompressionCodec.IsCompressed(plainText).ShouldBeFalse(); } [Fact] public void RoundTrip_LargePayload_Compresses() { // 10KB payload of repeated data should compress well var largePayload = new byte[10240]; var pattern = Encoding.UTF8.GetBytes("NATS route payload "); for (var i = 0; i < largePayload.Length; i++) largePayload[i] = pattern[i % pattern.Length]; var compressed = RouteCompressionCodec.Compress(largePayload, RouteCompressionLevel.Fast); // Compressed should be smaller than original for repetitive data compressed.Length.ShouldBeLessThan(largePayload.Length); // Round-trip should restore original var restored = RouteCompressionCodec.Decompress(compressed); restored.ShouldBe(largePayload); } }