github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/message/startup_test.go (about)

     1  // Copyright 2020 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 message
    16  
    17  import (
    18  	"bytes"
    19  	"errors"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  
    24  	"github.com/datastax/go-cassandra-native-protocol/primitive"
    25  )
    26  
    27  func TestStartup_DeepCopy(t *testing.T) {
    28  	msg := &Startup{
    29  		Options: map[string]string{
    30  			"opt1": "val1",
    31  			"opt2": "val2",
    32  		},
    33  	}
    34  
    35  	cloned := msg.DeepCopy()
    36  	assert.Equal(t, msg, cloned)
    37  
    38  	cloned.Options["opt1"] = "val5"
    39  	cloned.Options["opt3"] = "val6"
    40  
    41  	assert.NotEqual(t, msg, cloned)
    42  
    43  	assert.Equal(t, "val1", msg.Options["opt1"])
    44  	assert.Equal(t, "val2", msg.Options["opt2"])
    45  
    46  	assert.Equal(t, "val5", cloned.Options["opt1"])
    47  	assert.Equal(t, "val2", cloned.Options["opt2"])
    48  	assert.Equal(t, "val6", cloned.Options["opt3"])
    49  }
    50  
    51  func TestStartupCodec_Encode(t *testing.T) {
    52  	codec := &startupCodec{}
    53  	for _, version := range primitive.SupportedProtocolVersions() {
    54  		t.Run(version.String(), func(t *testing.T) {
    55  			tests := []struct {
    56  				name     string
    57  				input    Message
    58  				expected [][]byte // required because there can be multiple valid encodings
    59  				err      error
    60  			}{
    61  				{
    62  					"startup with default options",
    63  					NewStartup(),
    64  					[][]byte{{
    65  						0, 1, // map length
    66  						// key "CQL_VERSION"
    67  						0, 11, C, Q, L, __, V, E, R, S, I, O, N,
    68  						// value "3.0.0"
    69  						0, 5, _3, dot, _0, dot, _0,
    70  					}},
    71  					nil,
    72  				},
    73  				{
    74  					"startup with nil options",
    75  					&Startup{},
    76  					[][]byte{{0, 0}},
    77  					nil,
    78  				},
    79  				{
    80  					"startup with compression",
    81  					NewStartup(StartupOptionCompression, "LZ4"),
    82  					[][]byte{
    83  						{
    84  							0, 2,
    85  							// key "CQL_VERSION"
    86  							0, 11, C, Q, L, __, V, E, R, S, I, O, N,
    87  							// value "3.0.0"
    88  							0, 5, _3, dot, _0, dot, _0,
    89  							// key "COMPRESSION"
    90  							0, 11, C, O, M, P, R, E, S, S, I, O, N,
    91  							// value "LZ4"
    92  							0, 3, L, Z, _4,
    93  						},
    94  						{
    95  							0, 2,
    96  							// key "COMPRESSION"
    97  							0, 11, C, O, M, P, R, E, S, S, I, O, N,
    98  							// value "LZ4"
    99  							0, 3, L, Z, _4,
   100  							// key "CQL_VERSION"
   101  							0, 11, C, Q, L, __, V, E, R, S, I, O, N,
   102  							// value "3.0.0"
   103  							0, 5, _3, dot, _0, dot, _0,
   104  						},
   105  					},
   106  					nil,
   107  				},
   108  				{
   109  					"startup with custom options",
   110  					NewStartup(StartupOptionCqlVersion, "3.4.5", StartupOptionCompression, "SNAPPY"),
   111  					// we have two possible encodings because maps do not have deterministic iteration order
   112  					[][]byte{
   113  						{
   114  							0, 2, // map length
   115  							// key "CQL_VERSION"
   116  							0, 11, C, Q, L, __, V, E, R, S, I, O, N,
   117  							// value "3.4.5"
   118  							0, 5, _3, dot, _4, dot, _5,
   119  							// key "COMPRESSION"
   120  							0, 11, C, O, M, P, R, E, S, S, I, O, N,
   121  							// value "SNAPPY"
   122  							0, 6, S, N, A, P, P, Y,
   123  						},
   124  						{
   125  							0, 2, // map length
   126  							// key "COMPRESSION"
   127  							0, 11, C, O, M, P, R, E, S, S, I, O, N,
   128  							// value "SNAPPY"
   129  							0, 6, S, N, A, P, P, Y,
   130  							// key "CQL_VERSION"
   131  							0, 11, C, Q, L, __, V, E, R, S, I, O, N,
   132  							// value "3.4.5"
   133  							0, 5, _3, dot, _4, dot, _5,
   134  						},
   135  					},
   136  					nil,
   137  				},
   138  				{
   139  					"not a startup",
   140  					&Options{},
   141  					nil,
   142  					errors.New("expected *message.Startup, got *message.Options"),
   143  				},
   144  			}
   145  			for _, tt := range tests {
   146  				t.Run(tt.name, func(t *testing.T) {
   147  					dest := &bytes.Buffer{}
   148  					err := codec.Encode(tt.input, dest, version)
   149  					if err == nil {
   150  						assert.Contains(t, tt.expected, dest.Bytes())
   151  						assert.Nil(t, tt.err)
   152  					} else {
   153  						assert.Equal(t, tt.err, err)
   154  					}
   155  				})
   156  			}
   157  		})
   158  	}
   159  }
   160  
   161  func TestStartupCodec_EncodedLength(t *testing.T) {
   162  	codec := &startupCodec{}
   163  	tests := []struct {
   164  		name     string
   165  		input    Message
   166  		expected int
   167  		err      error
   168  	}{
   169  		{
   170  			"startup with default options",
   171  			NewStartup(),
   172  			primitive.LengthOfShort + // map length
   173  				primitive.LengthOfString("CQL_VERSION") + // map key
   174  				primitive.LengthOfString("3.0.0"), // map value
   175  			nil,
   176  		},
   177  		{
   178  			"startup with nil options",
   179  			&Startup{},
   180  			primitive.LengthOfShort, // map length
   181  			nil,
   182  		},
   183  		{
   184  			"startup with compression",
   185  			NewStartup(StartupOptionCompression, "LZ4"),
   186  			primitive.LengthOfShort + // map length
   187  				primitive.LengthOfString("CQL_VERSION") + // map key
   188  				primitive.LengthOfString("3.0.0") + // map value
   189  				primitive.LengthOfString("COMPRESSION") + // map key
   190  				primitive.LengthOfString("LZ4"), // map value
   191  			nil,
   192  		},
   193  		{
   194  			"startup with custom options",
   195  			NewStartup(StartupOptionCqlVersion, "3.4.5", StartupOptionCompression, "SNAPPY"),
   196  			primitive.LengthOfShort + // map length
   197  				primitive.LengthOfString("CQL_VERSION") + // map key
   198  				primitive.LengthOfString("3.4.5") + // map value
   199  				primitive.LengthOfString("COMPRESSION") + // map key
   200  				primitive.LengthOfString("SNAPPY"), // map value
   201  			nil,
   202  		},
   203  		{
   204  			"not a startup",
   205  			&Options{},
   206  			-1,
   207  			errors.New("expected *message.Startup, got *message.Options"),
   208  		},
   209  	}
   210  	for _, tt := range tests {
   211  		t.Run(tt.name, func(t *testing.T) {
   212  			for _, version := range primitive.SupportedProtocolVersions() {
   213  				t.Run(version.String(), func(t *testing.T) {
   214  					actual, err := codec.EncodedLength(tt.input, version)
   215  					assert.Equal(t, tt.expected, actual)
   216  					assert.Equal(t, tt.err, err)
   217  				})
   218  			}
   219  		})
   220  	}
   221  }
   222  
   223  func TestStartupCodec_Decode(t *testing.T) {
   224  	codec := &startupCodec{}
   225  	for _, version := range primitive.SupportedProtocolVersions() {
   226  		t.Run(version.String(), func(t *testing.T) {
   227  			tests := []decodeTestCase{
   228  				{
   229  					"startup with default options",
   230  					[]byte{
   231  						0, 1, // map length
   232  						// key "CQL_VERSION"
   233  						0, 11, C, Q, L, __, V, E, R, S, I, O, N,
   234  						// value "3.0.0"
   235  						0, 5, _3, dot, _0, dot, _0,
   236  					},
   237  					NewStartup(),
   238  					nil,
   239  				},
   240  				{
   241  					"startup with empty options",
   242  					[]byte{0, 0},
   243  					&Startup{Options: map[string]string{}},
   244  					nil,
   245  				},
   246  				{
   247  					"startup with compression",
   248  					[]byte{
   249  						0, 2,
   250  						// key "CQL_VERSION"
   251  						0, 11, C, Q, L, __, V, E, R, S, I, O, N,
   252  						// value "3.0.0"
   253  						0, 5, _3, dot, _0, dot, _0,
   254  						// key "COMPRESSION"
   255  						0, 11, C, O, M, P, R, E, S, S, I, O, N,
   256  						// value "LZ4"
   257  						0, 3, L, Z, _4,
   258  					},
   259  					NewStartup(StartupOptionCompression, "LZ4"),
   260  					nil,
   261  				},
   262  			}
   263  			for _, tt := range tests {
   264  				t.Run(tt.name, func(t *testing.T) {
   265  					source := bytes.NewBuffer(tt.input)
   266  					actual, err := codec.Decode(source, version)
   267  					assert.Equal(t, tt.expected, actual)
   268  					assert.Equal(t, tt.err, err)
   269  				})
   270  			}
   271  		})
   272  	}
   273  }