github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/segment/decode_test.go (about) 1 // Copyright 2021 DataStax 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package segment 16 17 import ( 18 "bytes" 19 "testing" 20 21 "github.com/stretchr/testify/assert" 22 23 "github.com/datastax/go-cassandra-native-protocol/compression/lz4" 24 "github.com/datastax/go-cassandra-native-protocol/crc" 25 ) 26 27 func Test_codec_DecodeSegment(t *testing.T) { 28 tests := []struct { 29 name string 30 compressor PayloadCompressor 31 source []byte 32 expected *Segment 33 expectErr bool 34 }{ 35 { 36 "payload 1 byte, self-contained, uncompressed", 37 nil, 38 []byte{ 39 // header 40 0b_00000001, // payload length bits 0-7 = 1 41 0b_00000000, // payload length bits 8-15 = 0 42 0b_000000_1_0, // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits) 43 0x72, 0x56, 0xac, // crc24 44 // payload 45 0b_00000001, // actual payload 46 0x0b, 0x2b, 0x9b, 0xba, // crc32 (already tested separately) 47 }, 48 &Segment{ 49 Header: &Header{ 50 IsSelfContained: true, 51 UncompressedPayloadLength: 1, 52 CompressedPayloadLength: 0, 53 Crc24: crc.ChecksumKoopman(0b_00000010_00000000_00000001, 3), 54 }, 55 Payload: &Payload{ 56 UncompressedData: []byte{1}, 57 Crc32: crc.ChecksumIEEE([]byte{1}), 58 }, 59 }, 60 false, 61 }, 62 { 63 "payload 1 byte, multi-part, uncompressed", 64 nil, 65 []byte{ 66 // header 67 0b_00000001, // payload length bits 0-7 = 1 68 0b_00000000, // payload length bits 8-15 = 0 69 0b_000000_0_0, // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits) 70 0x6f, 0x87, 0x15, // crc24 71 // payload 72 0b_00000001, // actual payload 73 0x0b, 0x2b, 0x9b, 0xba, // crc32 (already tested separately) 74 }, 75 &Segment{ 76 Header: &Header{ 77 IsSelfContained: false, 78 UncompressedPayloadLength: 1, 79 CompressedPayloadLength: 0, 80 Crc24: crc.ChecksumKoopman(0b_00000000_00000000_00000001, 3), 81 }, 82 Payload: &Payload{ 83 UncompressedData: []byte{1}, 84 Crc32: crc.ChecksumIEEE([]byte{1}), 85 }, 86 }, 87 false, 88 }, 89 { 90 "payload 10 bytes, self-contained, uncompressed", 91 nil, 92 []byte{ 93 // header 94 0b_00001010, // payload length bits 0-7 = 10 95 0b_00000000, // payload length bits 8-15 = 0 96 0b_000000_1_0, // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits) 97 0x8c, 0x68, 0x79, // crc24 98 // payload 99 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 100 0xa8, 0x32, 0xfa, 0xdf, // crc32 (already tested separately) 101 }, 102 &Segment{ 103 Header: &Header{ 104 IsSelfContained: true, 105 UncompressedPayloadLength: 10, 106 CompressedPayloadLength: 0, 107 Crc24: crc.ChecksumKoopman(0b_00000010_00000000_00001010, 3), 108 }, 109 Payload: &Payload{ 110 UncompressedData: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 111 Crc32: crc.ChecksumIEEE([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), 112 }, 113 }, 114 false, 115 }, 116 { 117 "payload 1 byte, self-contained, compressed", 118 lz4.Compressor{}, 119 []byte{ 120 // header 121 0b_00000010, // compressed payload length bits 0-7 = 2 122 0b_00000000, // compressed payload length bits 8-15 123 0b_0000001_0, // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 1 124 0b_00000000, // uncompressed payload length bits 7-14 125 0b_00000_1_00, // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits) 126 0x7a, 0x6, 0x9a, // crc24 127 // payload 128 0x10, 0x1, // compressed payload = {10, 1} 129 0xa8, 0xbe, 0xb4, 0x61, // crc32 (already tested separately) 130 }, 131 &Segment{ 132 Header: &Header{ 133 IsSelfContained: true, 134 UncompressedPayloadLength: 1, 135 CompressedPayloadLength: 2, 136 Crc24: crc.ChecksumKoopman(0b_00000100_00000000_00000010_00000000_00000010, 5), 137 }, 138 Payload: &Payload{ 139 UncompressedData: []byte{1}, 140 Crc32: crc.ChecksumIEEE([]byte{0x10, 0x1}), 141 }, 142 }, 143 false, 144 }, 145 { 146 "payload 1 byte, multi-part, compressed", 147 lz4.Compressor{}, 148 []byte{ 149 // header 150 0b_00000010, // compressed payload length bits 0-7 = 2 151 0b_00000000, // compressed payload length bits 8-15 152 0b_0000001_0, // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 1 153 0b_00000000, // uncompressed payload length bits 7-14 154 0b_00000_0_00, // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits) 155 0x4b, 0xeb, 0x7e, // crc24 156 // payload 157 0x10, 0x1, // compressed payload = {10, 1} 158 0xa8, 0xbe, 0xb4, 0x61, // crc32 (already tested separately) 159 }, 160 &Segment{ 161 Header: &Header{ 162 IsSelfContained: false, 163 UncompressedPayloadLength: 1, 164 CompressedPayloadLength: 2, 165 Crc24: crc.ChecksumKoopman(0b_00000000_00000000_00000010_00000000_00000010, 5), 166 }, 167 Payload: &Payload{ 168 UncompressedData: []byte{1}, 169 Crc32: crc.ChecksumIEEE([]byte{0x10, 0x1}), 170 }, 171 }, 172 false, 173 }, 174 { 175 "payload 10 bytes, self-contained, compressed", 176 lz4.Compressor{}, 177 []byte{ 178 // header 179 0b_00001011, // compressed payload length bits 0-7 = 11 180 0b_00000000, // compressed payload length bits 8-15 181 0b_0001010_0, // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 10 182 0b_00000000, // uncompressed payload length bits 7-14 183 0b_00000_1_00, // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits) 184 0x74, 0xcd, 0x7c, // crc24 185 // payload 186 0xa0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, // compressed payload 187 0x0e, 0xed, 0x34, 0x7b, // crc32 (already tested separately) 188 }, 189 &Segment{ 190 Header: &Header{ 191 IsSelfContained: true, 192 UncompressedPayloadLength: 10, 193 CompressedPayloadLength: 11, 194 Crc24: crc.ChecksumKoopman(0b_00000100_00000000_00010100_00000000_00001011, 5), 195 }, 196 Payload: &Payload{ 197 UncompressedData: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 198 Crc32: crc.ChecksumIEEE([]byte{0xa0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}), 199 }, 200 }, 201 false, 202 }, 203 { 204 "payload 10 bytes, self-contained, compressed header format but uncompressed", 205 lz4.Compressor{}, 206 []byte{ 207 // header 208 0b_00001011, // compressed payload length bits 0-7 = 11 209 0b_00000000, // compressed payload length bits 8-15 210 0b_0000000_0, // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 0 211 0b_00000000, // uncompressed payload length bits 7-14 212 0b_00000_1_00, // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits) 213 0xb3, 0x3f, 0x91, // crc24 214 // payload 215 0xa0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, // uncompressed payload 216 0x0e, 0xed, 0x34, 0x7b, // crc32 (already tested separately) 217 }, 218 &Segment{ 219 Header: &Header{ 220 IsSelfContained: true, 221 UncompressedPayloadLength: 11, 222 CompressedPayloadLength: 0, 223 Crc24: crc.ChecksumKoopman(0b_00000100_00000000_00000000_00000000_00001011, 5), 224 }, 225 Payload: &Payload{ 226 UncompressedData: []byte{0xa0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}, 227 Crc32: crc.ChecksumIEEE([]byte{0xa0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9}), 228 }, 229 }, 230 false, 231 }, 232 { 233 "wrong header CRC", 234 nil, 235 []byte{ 236 // header 237 0b_00000001, // payload length bits 0-7 = 1 238 0b_00000000, // payload length bits 8-15 = 0 239 0b_000000_1_0, // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits) 240 0x0, 0x0, 0x0, // crc24 241 // payload 242 0b_00000001, // actual payload 243 0x1b, 0xdf, 0x5, 0xa5, // crc32 (already tested separately) 244 }, 245 nil, 246 true, 247 }, 248 { 249 "wrong payload CRC", 250 nil, 251 []byte{ 252 // header 253 0b_00000001, // payload length bits 0-7 = 1 254 0b_00000000, // payload length bits 8-15 = 0 255 0b_000000_1_0, // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits) 256 0x72, 0x56, 0xac, // crc24 257 // payload 258 0b_00000001, // actual payload 259 0x0, 0x0, 0x0, 0x0, // crc32 260 }, 261 nil, 262 true, 263 }, 264 } 265 for _, tt := range tests { 266 t.Run(tt.name, func(t *testing.T) { 267 c := &codec{compressor: tt.compressor} 268 actual, err := c.DecodeSegment(bytes.NewReader(tt.source)) 269 if tt.expectErr { 270 assert.Error(t, err) 271 assert.Nil(t, actual) 272 } else { 273 assert.NoError(t, err) 274 assert.Equal(t, tt.expected, actual) 275 } 276 }) 277 } 278 } 279 280 func Test_codec_decodeSegmentHeader(t *testing.T) { 281 tests := []struct { 282 name string 283 compressor PayloadCompressor 284 source []byte 285 expected *Header 286 expectErr bool 287 }{ 288 { 289 "payload length 5, self contained, uncompressed", 290 nil, 291 []byte{ 292 0b_00000101, // payload length bits 0-7 = 5 293 0b_00000000, // payload length bits 8-15 = 0 294 0b_000000_1_0, // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits) 295 0x19, 0x99, 0x9a, // crc24 296 }, 297 &Header{ 298 IsSelfContained: true, 299 UncompressedPayloadLength: 5, 300 CompressedPayloadLength: 0, 301 Crc24: crc.ChecksumKoopman(0b_00000010_00000000_00000101, 3), 302 }, 303 false, 304 }, 305 { 306 "payload length 5, multi-part, uncompressed", 307 nil, 308 []byte{ 309 0b_00000101, // payload length bits 0-7 = 5 310 0b_00000000, // payload length bits 8-15 = 0 311 0b_000000_0_0, // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits) 312 0x4, 0x48, 0x23, // crc24 313 }, 314 &Header{ 315 IsSelfContained: false, 316 UncompressedPayloadLength: 5, 317 CompressedPayloadLength: 0, 318 Crc24: crc.ChecksumKoopman(0b_00000000_00000000_00000101, 3), 319 }, 320 false, 321 }, 322 { 323 "payload length max, uncompressed", 324 nil, 325 []byte{ 326 0b_11111111, // payload length bits 0-7 327 0b_11111111, // payload length bits 8-15 328 0b_000000_1_1, // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits) 329 0x25, 0x40, 0x47, // crc24 330 }, 331 &Header{ 332 IsSelfContained: true, 333 UncompressedPayloadLength: MaxPayloadLength, 334 CompressedPayloadLength: 0, 335 Crc24: crc.ChecksumKoopman(0b_00000011_11111111_11111111, 3), 336 }, 337 false, 338 }, 339 { 340 "payload length 5, self contained, compressed", 341 lz4.Compressor{}, 342 []byte{ 343 0b_00000101, // compressed payload length bits 0-7 = 5 344 0b_00000000, // compressed payload length bits 8-15 345 0b_0001100_0, // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 12 346 0b_00000000, // uncompressed payload length bits 7-14 347 0b_00000_1_00, // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits) 348 0x9e, 0x8, 0x38, // crc24 349 }, 350 &Header{ 351 IsSelfContained: true, 352 UncompressedPayloadLength: 12, 353 CompressedPayloadLength: 5, 354 Crc24: crc.ChecksumKoopman(0b_00000100_00000000_00011000_00000000_00000101, 5), 355 }, 356 false, 357 }, 358 { 359 "payload length 5, multi-part, compressed", 360 lz4.Compressor{}, 361 []byte{ 362 0b_00000101, // compressed payload length bits 0-7 = 5 363 0b_00000000, // compressed payload length bits 8-15 364 0b_0001100_0, // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 12 365 0b_00000000, // uncompressed payload length bits 7-14 366 0b_00000_0_00, // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits) 367 0xaf, 0xe5, 0xdc, // crc24 368 }, 369 &Header{ 370 IsSelfContained: false, 371 UncompressedPayloadLength: 12, 372 CompressedPayloadLength: 5, 373 Crc24: crc.ChecksumKoopman(0b_00000000_00000000_00011000_00000000_00000101, 5), 374 }, 375 false, 376 }, 377 { 378 "payload length max, compressed", 379 lz4.Compressor{}, 380 []byte{ 381 0b_01010000, // compressed payload length bits 0-7 382 0b_11000011, // compressed payload length bits 8-15 383 0b_1111111_0, // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 12 384 0b_11111111, // uncompressed payload length bits 7-14 385 0b_00000_1_11, // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits) 386 0xb4, 0x72, 0xaf, // crc24 387 }, 388 &Header{ 389 IsSelfContained: true, 390 UncompressedPayloadLength: MaxPayloadLength, 391 CompressedPayloadLength: 50_000, // 0_11000011_01010000 392 Crc24: crc.ChecksumKoopman(0b_00000111_11111111_11111110_11000011_01010000, 5), 393 }, 394 false, 395 }, 396 } 397 for _, tt := range tests { 398 t.Run(tt.name, func(t *testing.T) { 399 c := &codec{ 400 compressor: tt.compressor, 401 } 402 actual, err := c.decodeSegmentHeader(bytes.NewReader(tt.source)) 403 if tt.expectErr { 404 assert.Error(t, err) 405 } else { 406 assert.NoError(t, err) 407 assert.Equal(t, tt.expected, actual) 408 } 409 }) 410 } 411 }