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 }