github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/segment/encode_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  )
    25  
    26  func Test_codec_EncodeSegment(t *testing.T) {
    27  	tests := []struct {
    28  		name       string
    29  		compressor PayloadCompressor
    30  		segment    *Segment
    31  		expected   []byte
    32  		expectErr  bool
    33  	}{
    34  		{
    35  			"payload 1 byte, self-contained, uncompressed",
    36  			nil,
    37  			&Segment{
    38  				Header:  &Header{IsSelfContained: true},
    39  				Payload: &Payload{UncompressedData: []byte{1}},
    40  			},
    41  			[]byte{
    42  				// header
    43  				0b_00000001,      // payload length bits 0-7 = 1
    44  				0b_00000000,      // payload length bits 8-15 = 0
    45  				0b_000000_1_0,    // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits)
    46  				0x72, 0x56, 0xac, // crc24 (already tested separately)
    47  				// payload
    48  				0b_00000001,           // actual payload
    49  				0xb, 0x2b, 0x9b, 0xba, // crc32 (already tested separately)
    50  			},
    51  			false,
    52  		},
    53  		{
    54  			"payload 1 byte, multi-part, uncompressed",
    55  			nil,
    56  			&Segment{
    57  				Header:  &Header{IsSelfContained: false},
    58  				Payload: &Payload{UncompressedData: []byte{1}},
    59  			},
    60  			[]byte{
    61  				// header
    62  				0b_00000001,      // payload length bits 0-7 = 1
    63  				0b_00000000,      // payload length bits 8-15 = 0
    64  				0b_000000_0_0,    // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits)
    65  				0x6f, 0x87, 0x15, // crc24 (already tested separately)
    66  				// payload
    67  				0b_00000001,           // actual payload
    68  				0xb, 0x2b, 0x9b, 0xba, // crc32 (already tested separately)
    69  			},
    70  			false,
    71  		},
    72  		{
    73  			"payload 10 bytes, self-contained, uncompressed",
    74  			nil,
    75  			&Segment{
    76  				Header:  &Header{IsSelfContained: true},
    77  				Payload: &Payload{UncompressedData: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}},
    78  			},
    79  			[]byte{
    80  				// header
    81  				0b_00001010,      // payload length bits 0-7 = 10
    82  				0b_00000000,      // payload length bits 8-15 = 0
    83  				0b_000000_1_0,    // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits)
    84  				0x8c, 0x68, 0x79, // crc24 (already tested separately)
    85  				// payload
    86  				0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
    87  				0xa8, 0x32, 0xfa, 0xdf, // crc32 (already tested separately)
    88  			},
    89  			false,
    90  		},
    91  		{
    92  			"payload 1 byte, self-contained, compressed header format but uncompressed",
    93  			lz4.Compressor{},
    94  			&Segment{
    95  				Header:  &Header{IsSelfContained: true},
    96  				Payload: &Payload{UncompressedData: []byte{1}},
    97  			},
    98  			[]byte{
    99  				// header
   100  				0b_00000001,     // compressed payload length bits 0-7 = 1
   101  				0b_00000000,     // compressed payload length bits 8-15
   102  				0b_0000000_0,    // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 0
   103  				0b_00000000,     // uncompressed payload length bits 7-14
   104  				0b_00000_1_00,   // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits)
   105  				0x6, 0xa5, 0x87, // crc24 (already tested separately)
   106  				// payload
   107  				0x1,                   // uncompressed payload
   108  				0xb, 0x2b, 0x9b, 0xba, // crc32 (already tested separately)
   109  			},
   110  			false,
   111  		},
   112  		{
   113  			"payload 1 byte, multi-part, compressed header format but uncompressed",
   114  			lz4.Compressor{},
   115  			&Segment{
   116  				Header:  &Header{IsSelfContained: false},
   117  				Payload: &Payload{UncompressedData: []byte{1}},
   118  			},
   119  			[]byte{
   120  				// header
   121  				0b_00000001,      // compressed payload length bits 0-7 = 1
   122  				0b_00000000,      // compressed payload length bits 8-15
   123  				0b_0000000_0,     // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 0
   124  				0b_00000000,      // uncompressed payload length bits 7-14
   125  				0b_00000_0_00,    // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits)
   126  				0x37, 0x48, 0x63, // crc24 (already tested separately)
   127  				// payload
   128  				0x1,                   // uncompressed payload
   129  				0xb, 0x2b, 0x9b, 0xba, // crc32 (already tested separately)
   130  			},
   131  			false,
   132  		},
   133  		{
   134  			"payload 10 bytes, self-contained, compressed header format but uncompressed",
   135  			lz4.Compressor{},
   136  			&Segment{
   137  				Header:  &Header{IsSelfContained: true},
   138  				Payload: &Payload{UncompressedData: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}},
   139  			},
   140  			[]byte{
   141  				// header
   142  				0b_00001010,      // compressed payload length bits 0-7 = 10
   143  				0b_00000000,      // compressed payload length bits 8-15
   144  				0b_0000000_0,     // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 0
   145  				0b_00000000,      // uncompressed payload length bits 7-14
   146  				0b_00000_1_00,    // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits)
   147  				0x8e, 0xdb, 0x58, // crc24 (already tested separately)
   148  				// payload
   149  				0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // uncompressed payload
   150  				0xa8, 0x32, 0xfa, 0xdf, // crc32 (already tested separately)
   151  			},
   152  			false,
   153  		},
   154  		{
   155  			"payload 100 bytes, self-contained, compressed",
   156  			lz4.Compressor{},
   157  			&Segment{
   158  				Header:  &Header{IsSelfContained: true},
   159  				Payload: &Payload{UncompressedData: make([]byte, 100)},
   160  			},
   161  			[]byte{
   162  				// header
   163  				0b_00011010,      // compressed payload length bits 0-7 = 26
   164  				0b_00000000,      // compressed payload length bits 8-15
   165  				0b_1100100_0,     // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 100
   166  				0b_00000000,      // uncompressed payload length bits 7-14
   167  				0b_00000_1_00,    // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits)
   168  				0x3a, 0xc7, 0xd7, // crc24 (already tested separately)
   169  				// payload
   170  				0x1f, 0x0, 0x1, 0x0, 0x3a, 0x0, 0x2, 0x0, 0x0, 0x2, 0x0, 0xe0, 0x0,
   171  				0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // compressed payload
   172  				0x3e, 0x52, 0x70, 0xe4, // crc32 (already tested separately)
   173  			},
   174  			false,
   175  		},
   176  		{
   177  			"payload too large",
   178  			lz4.Compressor{},
   179  			&Segment{
   180  				Header:  &Header{IsSelfContained: true},
   181  				Payload: &Payload{UncompressedData: make([]byte, MaxPayloadLength+1)},
   182  			},
   183  			nil,
   184  			true,
   185  		},
   186  	}
   187  	for _, tt := range tests {
   188  		t.Run(tt.name, func(t *testing.T) {
   189  			c := &codec{compressor: tt.compressor}
   190  			actual := &bytes.Buffer{}
   191  			err := c.EncodeSegment(tt.segment, actual)
   192  			if tt.expectErr {
   193  				assert.Error(t, err)
   194  			} else {
   195  				assert.NoError(t, err)
   196  				assert.Equal(t, tt.expected, actual.Bytes())
   197  			}
   198  		})
   199  	}
   200  }
   201  
   202  func Test_codec_encodeHeaderUncompressed(t *testing.T) {
   203  	tests := []struct {
   204  		name      string
   205  		header    *Header
   206  		expected  []byte
   207  		expectErr bool
   208  	}{
   209  		{
   210  			"payload length 5, self contained",
   211  			&Header{
   212  				IsSelfContained:           true,
   213  				UncompressedPayloadLength: 5,
   214  			},
   215  			[]byte{
   216  				0b_00000101,      // payload length bits 0-7 = 5
   217  				0b_00000000,      // payload length bits 8-15 = 0
   218  				0b_000000_1_0,    // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits)
   219  				0x19, 0x99, 0x9a, // crc24 (already tested separately)
   220  			},
   221  			false,
   222  		},
   223  		{
   224  			"payload length 5, multi-part",
   225  			&Header{
   226  				IsSelfContained:           false,
   227  				UncompressedPayloadLength: 5,
   228  			},
   229  			[]byte{
   230  				0b_00000101,     // payload length bits 0-7 = 5
   231  				0b_00000000,     // payload length bits 8-15 = 0
   232  				0b_000000_0_0,   // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits)
   233  				0x4, 0x48, 0x23, // crc24 (already tested separately)
   234  			},
   235  			false,
   236  		},
   237  		{
   238  			"payload length max",
   239  			&Header{
   240  				IsSelfContained:           true,
   241  				UncompressedPayloadLength: MaxPayloadLength,
   242  			},
   243  			[]byte{
   244  				0b_11111111,      // payload length bits 0-7
   245  				0b_11111111,      // payload length bits 8-15
   246  				0b_000000_1_1,    // from right to left: payload length bit 16 + self-contained flag + header padding (6 bits)
   247  				0x25, 0x40, 0x47, // crc24 (already tested separately)
   248  			},
   249  			false,
   250  		},
   251  	}
   252  	for _, tt := range tests {
   253  		t.Run(tt.name, func(t *testing.T) {
   254  			c := &codec{}
   255  			actual := &bytes.Buffer{}
   256  			err := c.encodeHeaderUncompressed(tt.header, actual)
   257  			if tt.expectErr {
   258  				assert.Error(t, err)
   259  			} else {
   260  				assert.NoError(t, err)
   261  				assert.Equal(t, tt.expected, actual.Bytes())
   262  			}
   263  		})
   264  	}
   265  }
   266  
   267  func Test_codec_encodeHeaderCompressed(t *testing.T) {
   268  	tests := []struct {
   269  		name      string
   270  		header    *Header
   271  		expected  []byte
   272  		expectErr bool
   273  	}{
   274  		{
   275  			"payload length 5, self contained",
   276  			&Header{
   277  				IsSelfContained:           true,
   278  				UncompressedPayloadLength: 12,
   279  				CompressedPayloadLength:   5,
   280  			},
   281  			[]byte{
   282  				0b_00000101,     // compressed payload length bits 0-7 = 5
   283  				0b_00000000,     // compressed payload length bits 8-15
   284  				0b_0001100_0,    // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 12
   285  				0b_00000000,     // uncompressed payload length bits 7-14
   286  				0b_00000_1_00,   // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits)
   287  				0x9e, 0x8, 0x38, // crc24 (already tested separately)
   288  			},
   289  			false,
   290  		},
   291  		{
   292  			"payload length 5, multi-part",
   293  			&Header{
   294  				IsSelfContained:           false,
   295  				UncompressedPayloadLength: 12,
   296  				CompressedPayloadLength:   5,
   297  			},
   298  			[]byte{
   299  				0b_00000101,      // compressed payload length bits 0-7 = 5
   300  				0b_00000000,      // compressed payload length bits 8-15
   301  				0b_0001100_0,     // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 12
   302  				0b_00000000,      // uncompressed payload length bits 7-14
   303  				0b_00000_0_00,    // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits)
   304  				0xaf, 0xe5, 0xdc, // crc24 (already tested separately)
   305  			},
   306  			false,
   307  		},
   308  		{
   309  			"payload length max",
   310  			&Header{
   311  				IsSelfContained:           true,
   312  				UncompressedPayloadLength: MaxPayloadLength,
   313  				CompressedPayloadLength:   50_000, // 0_11000011_01010000
   314  			},
   315  			[]byte{
   316  				0b_01010000,      // compressed payload length bits 0-7
   317  				0b_11000011,      // compressed payload length bits 8-15
   318  				0b_1111111_0,     // from right to left: compressed payload length bit 16 + uncompressed payload length bits 0-6 = 12
   319  				0b_11111111,      // uncompressed payload length bits 7-14
   320  				0b_00000_1_11,    // from right to left: uncompressed payload length bits 15-16 + self-contained flag + header padding (5 bits)
   321  				0xb4, 0x72, 0xaf, // crc24 (already tested separately)
   322  			},
   323  			false,
   324  		},
   325  	}
   326  	for _, tt := range tests {
   327  		t.Run(tt.name, func(t *testing.T) {
   328  			c := &codec{}
   329  			actual := &bytes.Buffer{}
   330  			err := c.encodeHeaderCompressed(tt.header, actual)
   331  			if tt.expectErr {
   332  				assert.Error(t, err)
   333  			} else {
   334  				assert.NoError(t, err)
   335  				assert.Equal(t, tt.expected, actual.Bytes())
   336  			}
   337  		})
   338  	}
   339  }