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  }