github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/message/batch_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 TestBatch_Clone(t *testing.T) { 28 msg := &Batch{ 29 Type: primitive.BatchTypeLogged, 30 Children: []*BatchChild{{ 31 Query: "query", 32 Values: []*primitive.Value{{ 33 Type: primitive.ValueTypeRegular, 34 Contents: []byte{0x0a}, 35 }}, 36 }}, 37 Consistency: primitive.ConsistencyLevelLocalOne, 38 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelSerial), 39 DefaultTimestamp: int64Ptr(1), 40 Keyspace: "ks1", 41 NowInSeconds: int32Ptr(2), 42 } 43 cloned := msg.DeepCopy() 44 assert.Equal(t, msg, cloned) 45 cloned.Type = primitive.BatchTypeUnlogged 46 cloned.Children = []*BatchChild{{ 47 Query: "query2", 48 Values: []*primitive.Value{{ 49 Type: primitive.ValueTypeNull, 50 Contents: []byte{0x0b}, 51 }}, 52 }} 53 cloned.Consistency = primitive.ConsistencyLevelAll 54 cloned.SerialConsistency = consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial) 55 cloned.DefaultTimestamp = int64Ptr(5) 56 cloned.Keyspace = "ks2" 57 cloned.NowInSeconds = int32Ptr(9) 58 assert.Equal(t, "query", msg.Children[0].Query) 59 assert.Equal(t, "query2", cloned.Children[0].Query) 60 assert.Equal(t, primitive.BatchTypeLogged, msg.Type) 61 assert.Equal(t, primitive.BatchTypeUnlogged, cloned.Type) 62 assert.Equal(t, primitive.ConsistencyLevelLocalOne, msg.Consistency) 63 assert.Equal(t, primitive.ConsistencyLevelAll, cloned.Consistency) 64 assert.Equal(t, primitive.ConsistencyLevelSerial, *msg.SerialConsistency) 65 assert.Equal(t, primitive.ConsistencyLevelLocalSerial, *cloned.SerialConsistency) 66 assert.EqualValues(t, 1, *msg.DefaultTimestamp) 67 assert.EqualValues(t, 5, *cloned.DefaultTimestamp) 68 assert.Equal(t, "ks1", msg.Keyspace) 69 assert.Equal(t, "ks2", cloned.Keyspace) 70 assert.EqualValues(t, 2, *msg.NowInSeconds) 71 assert.EqualValues(t, 9, *cloned.NowInSeconds) 72 assert.NotEqual(t, msg, cloned) 73 } 74 75 func TestBatchCodec_Encode(t *testing.T) { 76 codec := &batchCodec{} 77 // version = 2 78 t.Run(primitive.ProtocolVersion2.String(), func(t *testing.T) { 79 tests := []encodeTestCase{ 80 { 81 "not a batch", 82 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 83 nil, 84 errors.New("expected *message.Batch, got *message.AuthChallenge"), 85 }, 86 { 87 "invalid batch type", 88 &Batch{Type: primitive.BatchType(42)}, 89 nil, 90 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 91 }, 92 { 93 "empty batch", 94 &Batch{}, 95 []byte{ 96 byte(primitive.BatchTypeLogged), 97 0, 0, // children count 98 0, 0, // consistency level 99 }, 100 nil, 101 }, 102 { 103 "batch with 2 children", 104 &Batch{ 105 Children: []*BatchChild{ 106 { 107 Query: "INSERT", 108 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 109 }, 110 { 111 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 112 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 113 }, 114 }, 115 }, 116 []byte{ 117 byte(primitive.BatchTypeLogged), 118 0, 2, // children count 119 0, // child 1 kind 120 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 121 0, 1, // child 1 values count 122 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 123 1, // child 2 kind 124 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 125 0, 1, // child 2 values count 126 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 127 0, 0, // consistency level 128 }, 129 nil, 130 }, 131 } 132 for _, tt := range tests { 133 t.Run(tt.name, func(t *testing.T) { 134 dest := &bytes.Buffer{} 135 err := codec.Encode(tt.input, dest, primitive.ProtocolVersion2) 136 assert.Equal(t, tt.expected, dest.Bytes()) 137 assert.Equal(t, tt.err, err) 138 }) 139 } 140 }) 141 // versions = 3, 4 142 for _, version := range []primitive.ProtocolVersion{primitive.ProtocolVersion3, primitive.ProtocolVersion4} { 143 t.Run(version.String(), func(t *testing.T) { 144 tests := []encodeTestCase{ 145 { 146 "not a batch", 147 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 148 nil, 149 errors.New("expected *message.Batch, got *message.AuthChallenge"), 150 }, 151 { 152 "invalid batch type", 153 &Batch{Type: primitive.BatchType(42)}, 154 nil, 155 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 156 }, 157 { 158 "empty batch", 159 &Batch{}, 160 []byte{ 161 byte(primitive.BatchTypeLogged), 162 0, 0, // children count 163 0, 0, // consistency level 164 0, // flags 165 }, 166 nil, 167 }, 168 { 169 "batch with 2 children", 170 &Batch{ 171 Children: []*BatchChild{ 172 { 173 Query: "INSERT", 174 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 175 }, 176 { 177 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 178 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 179 }, 180 }, 181 }, 182 []byte{ 183 byte(primitive.BatchTypeLogged), 184 0, 2, // children count 185 0, // child 1 kind 186 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 187 0, 1, // child 1 values count 188 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 189 1, // child 2 kind 190 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 191 0, 1, // child 2 values count 192 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 193 0, 0, // consistency level 194 0, // flags 195 }, 196 nil, 197 }, 198 { 199 "batch with custom options", 200 &Batch{ 201 Type: primitive.BatchTypeUnlogged, 202 Children: []*BatchChild{ 203 { 204 Query: "INSERT", 205 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 206 }, 207 }, 208 Consistency: primitive.ConsistencyLevelLocalQuorum, 209 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 210 DefaultTimestamp: int64Ptr(123), 211 }, 212 []byte{ 213 byte(primitive.BatchTypeUnlogged), 214 0, 1, // children count 215 0, // child 1 kind 216 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 217 0, 1, // child 1 values count 218 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 219 0, 6, // consistency 220 0b0011_0000, // flags 221 0, 9, // serial consistency 222 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 223 }, 224 nil, 225 }, 226 } 227 for _, tt := range tests { 228 t.Run(tt.name, func(t *testing.T) { 229 dest := &bytes.Buffer{} 230 err := codec.Encode(tt.input, dest, version) 231 assert.Equal(t, tt.expected, dest.Bytes()) 232 assert.Equal(t, tt.err, err) 233 }) 234 } 235 }) 236 } 237 // version = 5 238 t.Run(primitive.ProtocolVersion5.String(), func(t *testing.T) { 239 tests := []encodeTestCase{ 240 { 241 "not a batch", 242 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 243 nil, 244 errors.New("expected *message.Batch, got *message.AuthChallenge"), 245 }, 246 { 247 "invalid batch type", 248 &Batch{Type: primitive.BatchType(42)}, 249 nil, 250 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 251 }, 252 { 253 "empty batch", 254 &Batch{}, 255 []byte{ 256 byte(primitive.BatchTypeLogged), 257 0, 0, // children count 258 0, 0, // consistency level 259 0, 0, 0, 0, // flags 260 }, 261 nil, 262 }, 263 { 264 "batch with 2 children", 265 &Batch{ 266 Children: []*BatchChild{ 267 { 268 Query: "INSERT", 269 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 270 }, 271 { 272 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 273 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 274 }, 275 }, 276 }, 277 []byte{ 278 byte(primitive.BatchTypeLogged), 279 0, 2, // children count 280 0, // child 1 kind 281 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 282 0, 1, // child 1 values count 283 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 284 1, // child 2 kind 285 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 286 0, 1, // child 2 values count 287 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 288 0, 0, // consistency level 289 0, 0, 0, 0, // flags 290 }, 291 nil, 292 }, 293 { 294 "batch with custom options", 295 &Batch{ 296 Type: primitive.BatchTypeUnlogged, 297 Children: []*BatchChild{ 298 { 299 Query: "INSERT", 300 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 301 }, 302 }, 303 Consistency: primitive.ConsistencyLevelLocalQuorum, 304 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 305 DefaultTimestamp: int64Ptr(123), 306 Keyspace: "ks1", 307 NowInSeconds: int32Ptr(234), 308 }, 309 []byte{ 310 byte(primitive.BatchTypeUnlogged), 311 0, 1, // children count 312 0, // child 1 kind 313 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 314 0, 1, // child 1 values count 315 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 316 0, 6, // consistency 317 0b0000_0000, // flags 318 0b0000_0000, // flags 319 0b0000_0001, // flags => 0x100 (now in seconds) 320 0b1011_0000, // flags => 0x10 (serial) | 0x20 (timestamp) | 0x80 (keyspace) 321 0, 9, // serial consistency 322 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 323 0, 3, k, s, _1, // keyspace 324 0, 0, 0, 234, // now in seconds 325 }, 326 nil, 327 }, 328 } 329 for _, tt := range tests { 330 t.Run(tt.name, func(t *testing.T) { 331 dest := &bytes.Buffer{} 332 err := codec.Encode(tt.input, dest, primitive.ProtocolVersion5) 333 assert.Equal(t, tt.expected, dest.Bytes()) 334 assert.Equal(t, tt.err, err) 335 }) 336 } 337 }) 338 // version = DSE v1 339 t.Run(primitive.ProtocolVersionDse1.String(), func(t *testing.T) { 340 tests := []encodeTestCase{ 341 { 342 "not a batch", 343 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 344 nil, 345 errors.New("expected *message.Batch, got *message.AuthChallenge"), 346 }, 347 { 348 "invalid batch type", 349 &Batch{Type: primitive.BatchType(42)}, 350 nil, 351 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 352 }, 353 { 354 "empty batch", 355 &Batch{}, 356 []byte{ 357 byte(primitive.BatchTypeLogged), 358 0, 0, // children count 359 0, 0, // consistency level 360 0, 0, 0, 0, // flags 361 }, 362 nil, 363 }, 364 { 365 "batch with 2 children", 366 &Batch{ 367 Children: []*BatchChild{ 368 { 369 Query: "INSERT", 370 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 371 }, 372 { 373 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 374 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 375 }, 376 }, 377 }, 378 []byte{ 379 byte(primitive.BatchTypeLogged), 380 0, 2, // children count 381 0, // child 1 kind 382 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 383 0, 1, // child 1 values count 384 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 385 1, // child 2 kind 386 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 387 0, 1, // child 2 values count 388 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 389 0, 0, // consistency level 390 0, 0, 0, 0, // flags 391 }, 392 nil, 393 }, 394 { 395 "batch with custom options", 396 &Batch{ 397 Type: primitive.BatchTypeUnlogged, 398 Children: []*BatchChild{ 399 { 400 Query: "INSERT", 401 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 402 }, 403 }, 404 Consistency: primitive.ConsistencyLevelLocalQuorum, 405 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 406 DefaultTimestamp: int64Ptr(123), 407 }, 408 []byte{ 409 byte(primitive.BatchTypeUnlogged), 410 0, 1, // children count 411 0, // child 1 kind 412 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 413 0, 1, // child 1 values count 414 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 415 0, 6, // consistency 416 0, 0, 0, 0b0011_0000, // flags 0x10 (serial) | 0x20 (timestamp) 417 0, 9, // serial consistency 418 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 419 }, 420 nil, 421 }, 422 } 423 for _, tt := range tests { 424 t.Run(tt.name, func(t *testing.T) { 425 dest := &bytes.Buffer{} 426 err := codec.Encode(tt.input, dest, primitive.ProtocolVersionDse1) 427 assert.Equal(t, tt.expected, dest.Bytes()) 428 assert.Equal(t, tt.err, err) 429 }) 430 } 431 }) 432 // version = DSE v2 433 t.Run(primitive.ProtocolVersionDse2.String(), func(t *testing.T) { 434 tests := []encodeTestCase{ 435 { 436 "not a batch", 437 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 438 nil, 439 errors.New("expected *message.Batch, got *message.AuthChallenge"), 440 }, 441 { 442 "invalid batch type", 443 &Batch{Type: primitive.BatchType(42)}, 444 nil, 445 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 446 }, 447 { 448 "empty batch", 449 &Batch{}, 450 []byte{ 451 byte(primitive.BatchTypeLogged), 452 0, 0, // children count 453 0, 0, // consistency level 454 0, 0, 0, 0, // flags 455 }, 456 nil, 457 }, 458 { 459 "batch with 2 children", 460 &Batch{ 461 Children: []*BatchChild{ 462 { 463 Query: "INSERT", 464 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 465 }, 466 { 467 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 468 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 469 }, 470 }, 471 }, 472 []byte{ 473 byte(primitive.BatchTypeLogged), 474 0, 2, // children count 475 0, // child 1 kind 476 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 477 0, 1, // child 1 values count 478 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 479 1, // child 2 kind 480 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 481 0, 1, // child 2 values count 482 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 483 0, 0, // consistency level 484 0, 0, 0, 0, // flags 485 }, 486 nil, 487 }, 488 { 489 "batch with custom options", 490 &Batch{ 491 Type: primitive.BatchTypeUnlogged, 492 Children: []*BatchChild{ 493 { 494 Query: "INSERT", 495 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 496 }, 497 }, 498 Consistency: primitive.ConsistencyLevelLocalQuorum, 499 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 500 DefaultTimestamp: int64Ptr(123), 501 Keyspace: "ks1", 502 }, 503 []byte{ 504 byte(primitive.BatchTypeUnlogged), 505 0, 1, // children count 506 0, // child 1 kind 507 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 508 0, 1, // child 1 values count 509 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 510 0, 6, // consistency 511 0b0000_0000, // flags 512 0b0000_0000, // flags 513 0b0000_0000, // flags 514 0b1011_0000, // flags => 0x10 (serial) | 0x20 (timestamp) | 0x80 (keyspace) 515 0, 9, // serial consistency 516 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 517 0, 3, k, s, _1, // keyspace 518 }, 519 nil, 520 }, 521 } 522 for _, tt := range tests { 523 t.Run(tt.name, func(t *testing.T) { 524 dest := &bytes.Buffer{} 525 err := codec.Encode(tt.input, dest, primitive.ProtocolVersionDse2) 526 assert.Equal(t, tt.expected, dest.Bytes()) 527 assert.Equal(t, tt.err, err) 528 }) 529 } 530 }) 531 } 532 533 func TestBatchCodec_EncodedLength(t *testing.T) { 534 codec := &batchCodec{} 535 // version = 2 536 t.Run(primitive.ProtocolVersion2.String(), func(t *testing.T) { 537 tests := []encodedLengthTestCase{ 538 { 539 "not a batch", 540 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 541 -1, 542 errors.New("expected *message.Batch, got *message.AuthChallenge"), 543 }, 544 { 545 "empty batch", 546 &Batch{}, 547 primitive.LengthOfByte + 548 primitive.LengthOfShort + // children count 549 primitive.LengthOfShort, // consistency 550 nil, 551 }, 552 { 553 "batch with 2 children", 554 &Batch{ 555 Children: []*BatchChild{ 556 { 557 Query: "INSERT", 558 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 559 }, 560 { 561 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 562 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 563 }, 564 }, 565 }, 566 primitive.LengthOfByte + 567 primitive.LengthOfShort + // children count 568 primitive.LengthOfByte + // child 1 kind 569 primitive.LengthOfLongString("INSERT") + // child 1 query 570 primitive.LengthOfShort + // child values count 571 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 1 value 1 572 primitive.LengthOfByte + // child 2 kind 573 primitive.LengthOfShortBytes([]byte{0xca, 0xfe, 0xba, 0xbe}) + // child 1 query 574 primitive.LengthOfShort + // child values count 575 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 2 value 1 576 primitive.LengthOfShort, // consistency 577 nil, 578 }, 579 } 580 for _, tt := range tests { 581 t.Run(tt.name, func(t *testing.T) { 582 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersion2) 583 assert.Equal(t, tt.expected, actual) 584 assert.Equal(t, tt.err, err) 585 }) 586 } 587 }) 588 // versions = 3, 4 589 for _, version := range []primitive.ProtocolVersion{primitive.ProtocolVersion3, primitive.ProtocolVersion4} { 590 t.Run(version.String(), func(t *testing.T) { 591 tests := []encodedLengthTestCase{ 592 { 593 "not a batch", 594 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 595 -1, 596 errors.New("expected *message.Batch, got *message.AuthChallenge"), 597 }, 598 { 599 "empty batch", 600 &Batch{}, 601 primitive.LengthOfByte + 602 primitive.LengthOfShort + // children count 603 primitive.LengthOfShort + // consistency 604 primitive.LengthOfByte, // flags 605 nil, 606 }, 607 { 608 "batch with 2 children", 609 &Batch{ 610 Children: []*BatchChild{ 611 { 612 Query: "INSERT", 613 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 614 }, 615 { 616 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 617 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 618 }, 619 }, 620 }, 621 primitive.LengthOfByte + 622 primitive.LengthOfShort + // children count 623 primitive.LengthOfByte + // child 1 kind 624 primitive.LengthOfLongString("INSERT") + // child 1 query 625 primitive.LengthOfShort + // child values count 626 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 1 value 1 627 primitive.LengthOfByte + // child 2 kind 628 primitive.LengthOfShortBytes([]byte{0xca, 0xfe, 0xba, 0xbe}) + // child 1 query 629 primitive.LengthOfShort + // child values count 630 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 2 value 1 631 primitive.LengthOfShort + // consistency 632 primitive.LengthOfByte, // flags 633 nil, 634 }, 635 { 636 "batch with custom options", 637 &Batch{ 638 Type: primitive.BatchTypeUnlogged, 639 Children: []*BatchChild{ 640 { 641 Query: "INSERT", 642 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 643 }, 644 }, 645 Consistency: primitive.ConsistencyLevelLocalQuorum, 646 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 647 DefaultTimestamp: int64Ptr(123), 648 }, 649 primitive.LengthOfByte + 650 primitive.LengthOfShort + // children count 651 primitive.LengthOfByte + // child 1 kind 652 primitive.LengthOfLongString("INSERT") + // child 1 query 653 primitive.LengthOfShort + // child values count 654 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 1 value 1 655 primitive.LengthOfShort + // consistency 656 primitive.LengthOfByte + // flags 657 primitive.LengthOfShort + // serial consistency 658 primitive.LengthOfLong, // default timestamp 659 nil, 660 }, 661 } 662 for _, tt := range tests { 663 t.Run(tt.name, func(t *testing.T) { 664 actual, err := codec.EncodedLength(tt.input, version) 665 assert.Equal(t, tt.expected, actual) 666 assert.Equal(t, tt.err, err) 667 }) 668 } 669 }) 670 } 671 // version = 5 672 t.Run(primitive.ProtocolVersion5.String(), func(t *testing.T) { 673 tests := []encodedLengthTestCase{ 674 { 675 "not a batch", 676 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 677 -1, 678 errors.New("expected *message.Batch, got *message.AuthChallenge"), 679 }, 680 { 681 "empty batch", 682 &Batch{}, 683 primitive.LengthOfByte + 684 primitive.LengthOfShort + // children count 685 primitive.LengthOfShort + // consistency 686 primitive.LengthOfInt, // flags 687 nil, 688 }, 689 { 690 "batch with 2 children", 691 &Batch{ 692 Children: []*BatchChild{ 693 { 694 Query: "INSERT", 695 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 696 }, 697 { 698 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 699 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 700 }, 701 }, 702 }, 703 primitive.LengthOfByte + 704 primitive.LengthOfShort + // children count 705 primitive.LengthOfByte + // child 1 kind 706 primitive.LengthOfLongString("INSERT") + // child 1 query 707 primitive.LengthOfShort + // child values count 708 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 1 value 1 709 primitive.LengthOfByte + // child 2 kind 710 primitive.LengthOfShortBytes([]byte{0xca, 0xfe, 0xba, 0xbe}) + // child 1 query 711 primitive.LengthOfShort + // child values count 712 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 2 value 1 713 primitive.LengthOfShort + // consistency 714 primitive.LengthOfInt, // flags 715 nil, 716 }, 717 { 718 "batch with custom options", 719 &Batch{ 720 Type: primitive.BatchTypeUnlogged, 721 Children: []*BatchChild{ 722 { 723 Query: "INSERT", 724 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 725 }, 726 }, 727 Consistency: primitive.ConsistencyLevelLocalQuorum, 728 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 729 DefaultTimestamp: int64Ptr(123), 730 Keyspace: "ks1", 731 NowInSeconds: int32Ptr(234), 732 }, 733 primitive.LengthOfByte + 734 primitive.LengthOfShort + // children count 735 primitive.LengthOfByte + // child 1 kind 736 primitive.LengthOfLongString("INSERT") + // child 1 query 737 primitive.LengthOfShort + // child values count 738 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 1 value 1 739 primitive.LengthOfShort + // consistency 740 primitive.LengthOfInt + // flags 741 primitive.LengthOfShort + // serial consistency 742 primitive.LengthOfLong + // default timestamp 743 primitive.LengthOfString("ks1") + // keyspace 744 primitive.LengthOfInt, // now in seconds 745 nil, 746 }, 747 } 748 for _, tt := range tests { 749 t.Run(tt.name, func(t *testing.T) { 750 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersion5) 751 assert.Equal(t, tt.expected, actual) 752 assert.Equal(t, tt.err, err) 753 }) 754 } 755 }) 756 // version = DSE v1 757 t.Run(primitive.ProtocolVersionDse1.String(), func(t *testing.T) { 758 tests := []encodedLengthTestCase{ 759 { 760 "not a batch", 761 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 762 -1, 763 errors.New("expected *message.Batch, got *message.AuthChallenge"), 764 }, 765 { 766 "empty batch", 767 &Batch{}, 768 primitive.LengthOfByte + 769 primitive.LengthOfShort + // children count 770 primitive.LengthOfShort + // consistency 771 primitive.LengthOfInt, // flags 772 nil, 773 }, 774 { 775 "batch with 2 children", 776 &Batch{ 777 Children: []*BatchChild{ 778 { 779 Query: "INSERT", 780 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 781 }, 782 { 783 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 784 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 785 }, 786 }, 787 }, 788 primitive.LengthOfByte + 789 primitive.LengthOfShort + // children count 790 primitive.LengthOfByte + // child 1 kind 791 primitive.LengthOfLongString("INSERT") + // child 1 query 792 primitive.LengthOfShort + // child values count 793 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 1 value 1 794 primitive.LengthOfByte + // child 2 kind 795 primitive.LengthOfShortBytes([]byte{0xca, 0xfe, 0xba, 0xbe}) + // child 1 query 796 primitive.LengthOfShort + // child values count 797 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 2 value 1 798 primitive.LengthOfShort + // consistency 799 primitive.LengthOfInt, // flags 800 nil, 801 }, 802 { 803 "batch with custom options", 804 &Batch{ 805 Type: primitive.BatchTypeUnlogged, 806 Children: []*BatchChild{ 807 { 808 Query: "INSERT", 809 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 810 }, 811 }, 812 Consistency: primitive.ConsistencyLevelLocalQuorum, 813 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 814 DefaultTimestamp: int64Ptr(123), 815 }, 816 primitive.LengthOfByte + 817 primitive.LengthOfShort + // children count 818 primitive.LengthOfByte + // child 1 kind 819 primitive.LengthOfLongString("INSERT") + // child 1 query 820 primitive.LengthOfShort + // child values count 821 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 1 value 1 822 primitive.LengthOfShort + // consistency 823 primitive.LengthOfInt + // flags 824 primitive.LengthOfShort + // serial consistency 825 primitive.LengthOfLong, // default timestamp 826 nil, 827 }, 828 } 829 for _, tt := range tests { 830 t.Run(tt.name, func(t *testing.T) { 831 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersionDse1) 832 assert.Equal(t, tt.expected, actual) 833 assert.Equal(t, tt.err, err) 834 }) 835 } 836 }) 837 // version = DSE v2 838 t.Run(primitive.ProtocolVersionDse2.String(), func(t *testing.T) { 839 tests := []encodedLengthTestCase{ 840 { 841 "not a batch", 842 &AuthChallenge{[]byte{0xca, 0xfe, 0xba, 0xbe}}, 843 -1, 844 errors.New("expected *message.Batch, got *message.AuthChallenge"), 845 }, 846 { 847 "empty batch", 848 &Batch{}, 849 primitive.LengthOfByte + 850 primitive.LengthOfShort + // children count 851 primitive.LengthOfShort + // consistency 852 primitive.LengthOfInt, // flags 853 nil, 854 }, 855 { 856 "batch with 2 children", 857 &Batch{ 858 Children: []*BatchChild{ 859 { 860 Query: "INSERT", 861 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 862 }, 863 { 864 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 865 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 866 }, 867 }, 868 }, 869 primitive.LengthOfByte + 870 primitive.LengthOfShort + // children count 871 primitive.LengthOfByte + // child 1 kind 872 primitive.LengthOfLongString("INSERT") + // child 1 query 873 primitive.LengthOfShort + // child values count 874 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 1 value 1 875 primitive.LengthOfByte + // child 2 kind 876 primitive.LengthOfShortBytes([]byte{0xca, 0xfe, 0xba, 0xbe}) + // child 1 query 877 primitive.LengthOfShort + // child values count 878 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 2 value 1 879 primitive.LengthOfShort + // consistency 880 primitive.LengthOfInt, // flags 881 nil, 882 }, 883 { 884 "batch with custom options", 885 &Batch{ 886 Type: primitive.BatchTypeUnlogged, 887 Children: []*BatchChild{ 888 { 889 Query: "INSERT", 890 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 891 }, 892 }, 893 Consistency: primitive.ConsistencyLevelLocalQuorum, 894 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 895 DefaultTimestamp: int64Ptr(123), 896 Keyspace: "ks1", 897 }, 898 primitive.LengthOfByte + 899 primitive.LengthOfShort + // children count 900 primitive.LengthOfByte + // child 1 kind 901 primitive.LengthOfLongString("INSERT") + // child 1 query 902 primitive.LengthOfShort + // child values count 903 primitive.LengthOfInt + len([]byte{1, 2, 3, 4}) + // child 1 value 1 904 primitive.LengthOfShort + // consistency 905 primitive.LengthOfInt + // flags 906 primitive.LengthOfShort + // serial consistency 907 primitive.LengthOfLong + // default timestamp 908 primitive.LengthOfString("ks1"), // keyspace 909 nil, 910 }, 911 } 912 for _, tt := range tests { 913 t.Run(tt.name, func(t *testing.T) { 914 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersionDse2) 915 assert.Equal(t, tt.expected, actual) 916 assert.Equal(t, tt.err, err) 917 }) 918 } 919 }) 920 } 921 922 func TestBatchCodec_Decode(t *testing.T) { 923 codec := &batchCodec{} 924 // version = 2 925 t.Run(primitive.ProtocolVersion2.String(), func(t *testing.T) { 926 tests := []decodeTestCase{ 927 { 928 "invalid batch type", 929 []byte{ 930 42, // bach type 931 0, 0, // children count 932 0, 0, // consistency level 933 0, // flags 934 }, 935 nil, 936 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 937 }, 938 { 939 "empty batch", 940 []byte{ 941 byte(primitive.BatchTypeLogged), 942 0, 0, // children count 943 0, 0, // consistency level 944 }, 945 &Batch{Children: []*BatchChild{}}, 946 nil, 947 }, 948 { 949 "batch with 2 children", 950 []byte{ 951 byte(primitive.BatchTypeLogged), 952 0, 2, // children count 953 0, // child 1 kind 954 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 955 0, 1, // child 1 values count 956 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 957 1, // child 2 kind 958 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 959 0, 1, // child 2 values count 960 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 961 0, 0, // consistency level 962 }, 963 &Batch{ 964 Children: []*BatchChild{ 965 { 966 Query: "INSERT", 967 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 968 }, 969 { 970 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 971 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 972 }, 973 }, 974 }, 975 nil, 976 }, 977 } 978 for _, tt := range tests { 979 t.Run(tt.name, func(t *testing.T) { 980 source := bytes.NewBuffer(tt.input) 981 actual, err := codec.Decode(source, primitive.ProtocolVersion2) 982 assert.Equal(t, tt.expected, actual) 983 assert.Equal(t, tt.err, err) 984 }) 985 } 986 }) 987 // versions = 3, 4 988 for _, version := range []primitive.ProtocolVersion{primitive.ProtocolVersion3, primitive.ProtocolVersion4} { 989 t.Run(version.String(), func(t *testing.T) { 990 tests := []decodeTestCase{ 991 { 992 "invalid batch type", 993 []byte{ 994 42, // bach type 995 0, 0, // children count 996 0, 0, // consistency level 997 0, // flags 998 }, 999 nil, 1000 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 1001 }, 1002 { 1003 "empty batch", 1004 []byte{ 1005 byte(primitive.BatchTypeLogged), 1006 0, 0, // children count 1007 0, 0, // consistency level 1008 0, // flags 1009 }, 1010 &Batch{Children: []*BatchChild{}}, 1011 nil, 1012 }, 1013 { 1014 "batch with 2 children", 1015 []byte{ 1016 byte(primitive.BatchTypeLogged), 1017 0, 2, // children count 1018 0, // child 1 kind 1019 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 1020 0, 1, // child 1 values count 1021 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 1022 1, // child 2 kind 1023 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 1024 0, 1, // child 2 values count 1025 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 1026 0, 0, // consistency level 1027 0, // flags 1028 }, 1029 &Batch{ 1030 Children: []*BatchChild{ 1031 { 1032 Query: "INSERT", 1033 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 1034 }, 1035 { 1036 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 1037 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 1038 }, 1039 }, 1040 }, 1041 nil, 1042 }, 1043 { 1044 "batch with custom options", 1045 []byte{ 1046 byte(primitive.BatchTypeUnlogged), 1047 0, 1, // children count 1048 0, // child 1 kind 1049 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 1050 0, 1, // child 1 values count 1051 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 1052 0, 6, // consistency 1053 0b0011_0000, // flags 1054 0, 9, // serial consistency 1055 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 1056 }, 1057 &Batch{ 1058 Type: primitive.BatchTypeUnlogged, 1059 Children: []*BatchChild{ 1060 { 1061 Query: "INSERT", 1062 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 1063 }, 1064 }, 1065 Consistency: primitive.ConsistencyLevelLocalQuorum, 1066 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1067 DefaultTimestamp: int64Ptr(123), 1068 }, 1069 nil, 1070 }, 1071 } 1072 for _, tt := range tests { 1073 t.Run(tt.name, func(t *testing.T) { 1074 source := bytes.NewBuffer(tt.input) 1075 actual, err := codec.Decode(source, version) 1076 assert.Equal(t, tt.expected, actual) 1077 assert.Equal(t, tt.err, err) 1078 }) 1079 } 1080 }) 1081 } 1082 // version = 5 1083 t.Run(primitive.ProtocolVersion5.String(), func(t *testing.T) { 1084 tests := []decodeTestCase{ 1085 { 1086 "invalid batch type", 1087 []byte{ 1088 42, // bach type 1089 0, 0, // children count 1090 0, 0, // consistency level 1091 0, 0, 0, 0, // flags 1092 }, 1093 nil, 1094 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 1095 }, 1096 { 1097 "empty batch", 1098 []byte{ 1099 byte(primitive.BatchTypeLogged), 1100 0, 0, // children count 1101 0, 0, // consistency level 1102 0, 0, 0, 0, // flags 1103 }, 1104 &Batch{Children: []*BatchChild{}}, 1105 nil, 1106 }, 1107 { 1108 "batch with 2 children", 1109 []byte{ 1110 byte(primitive.BatchTypeLogged), 1111 0, 2, // children count 1112 0, // child 1 kind 1113 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 1114 0, 1, // child 1 values count 1115 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 1116 1, // child 2 kind 1117 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 1118 0, 1, // child 2 values count 1119 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 1120 0, 0, // consistency level 1121 0, 0, 0, 0, // flags 1122 }, 1123 &Batch{ 1124 Children: []*BatchChild{ 1125 { 1126 Query: "INSERT", 1127 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 1128 }, 1129 { 1130 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 1131 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 1132 }, 1133 }, 1134 }, 1135 nil, 1136 }, 1137 { 1138 "batch with custom options", 1139 []byte{ 1140 byte(primitive.BatchTypeUnlogged), 1141 0, 1, // children count 1142 0, // child 1 kind 1143 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 1144 0, 1, // child 1 values count 1145 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 1146 0, 6, // consistency 1147 0b0000_0000, // flags 1148 0b0000_0000, // flags 1149 0b0000_0001, // flags => 0x100 (now in seconds) 1150 0b1011_0000, // flags => 0x10 (serial) | 0x20 (timestamp) | 0x80 (keyspace) 1151 0, 9, // serial consistency 1152 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 1153 0, 3, k, s, _1, // keyspace 1154 0, 0, 0, 234, // now in seconds 1155 }, 1156 &Batch{ 1157 Type: primitive.BatchTypeUnlogged, 1158 Children: []*BatchChild{ 1159 { 1160 Query: "INSERT", 1161 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 1162 }, 1163 }, 1164 Consistency: primitive.ConsistencyLevelLocalQuorum, 1165 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1166 DefaultTimestamp: int64Ptr(123), 1167 Keyspace: "ks1", 1168 NowInSeconds: int32Ptr(234), 1169 }, 1170 nil, 1171 }, 1172 } 1173 for _, tt := range tests { 1174 t.Run(tt.name, func(t *testing.T) { 1175 source := bytes.NewBuffer(tt.input) 1176 actual, err := codec.Decode(source, primitive.ProtocolVersion5) 1177 assert.Equal(t, tt.expected, actual) 1178 assert.Equal(t, tt.err, err) 1179 }) 1180 } 1181 }) 1182 // version = DSE v1 1183 t.Run(primitive.ProtocolVersionDse1.String(), func(t *testing.T) { 1184 tests := []decodeTestCase{ 1185 { 1186 "invalid batch type", 1187 []byte{ 1188 42, // bach type 1189 0, 0, // children count 1190 0, 0, // consistency level 1191 0, 0, 0, 0, // flags 1192 }, 1193 nil, 1194 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 1195 }, 1196 { 1197 "empty batch", 1198 []byte{ 1199 byte(primitive.BatchTypeLogged), 1200 0, 0, // children count 1201 0, 0, // consistency level 1202 0, 0, 0, 0, // flags 1203 }, 1204 &Batch{Children: []*BatchChild{}}, 1205 nil, 1206 }, 1207 { 1208 "batch with 2 children", 1209 []byte{ 1210 byte(primitive.BatchTypeLogged), 1211 0, 2, // children count 1212 0, // child 1 kind 1213 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 1214 0, 1, // child 1 values count 1215 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 1216 1, // child 2 kind 1217 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 1218 0, 1, // child 2 values count 1219 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 1220 0, 0, // consistency level 1221 0, 0, 0, 0, // flags 1222 }, 1223 &Batch{ 1224 Children: []*BatchChild{ 1225 { 1226 Query: "INSERT", 1227 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 1228 }, 1229 { 1230 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 1231 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 1232 }, 1233 }, 1234 }, 1235 nil, 1236 }, 1237 { 1238 "batch with custom options", 1239 []byte{ 1240 byte(primitive.BatchTypeUnlogged), 1241 0, 1, // children count 1242 0, // child 1 kind 1243 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 1244 0, 1, // child 1 values count 1245 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 1246 0, 6, // consistency 1247 0, 0, 0, 0b0011_0000, // flags 1248 0, 9, // serial consistency 1249 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 1250 }, 1251 &Batch{ 1252 Type: primitive.BatchTypeUnlogged, 1253 Children: []*BatchChild{ 1254 { 1255 Query: "INSERT", 1256 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 1257 }, 1258 }, 1259 Consistency: primitive.ConsistencyLevelLocalQuorum, 1260 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1261 DefaultTimestamp: int64Ptr(123), 1262 }, 1263 nil, 1264 }, 1265 } 1266 for _, tt := range tests { 1267 t.Run(tt.name, func(t *testing.T) { 1268 source := bytes.NewBuffer(tt.input) 1269 actual, err := codec.Decode(source, primitive.ProtocolVersionDse1) 1270 assert.Equal(t, tt.expected, actual) 1271 assert.Equal(t, tt.err, err) 1272 }) 1273 } 1274 }) 1275 // version = DSE v2 1276 t.Run(primitive.ProtocolVersionDse2.String(), func(t *testing.T) { 1277 tests := []decodeTestCase{ 1278 { 1279 "invalid batch type", 1280 []byte{ 1281 42, // bach type 1282 0, 0, // children count 1283 0, 0, // consistency level 1284 0, 0, 0, 0, // flags 1285 }, 1286 nil, 1287 errors.New("invalid BATCH type: BatchType ? [0X2A]"), 1288 }, 1289 { 1290 "empty batch", 1291 []byte{ 1292 byte(primitive.BatchTypeLogged), 1293 0, 0, // children count 1294 0, 0, // consistency level 1295 0, 0, 0, 0, // flags 1296 }, 1297 &Batch{Children: []*BatchChild{}}, 1298 nil, 1299 }, 1300 { 1301 "batch with 2 children", 1302 []byte{ 1303 byte(primitive.BatchTypeLogged), 1304 0, 2, // children count 1305 0, // child 1 kind 1306 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 1307 0, 1, // child 1 values count 1308 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 1309 1, // child 2 kind 1310 0, 4, 0xca, 0xfe, 0xba, 0xbe, // child 2 query id 1311 0, 1, // child 2 values count 1312 0, 0, 0, 4, 5, 6, 7, 8, // child 2 value 1 1313 0, 0, // consistency level 1314 0, 0, 0, 0, // flags 1315 }, 1316 &Batch{ 1317 Children: []*BatchChild{ 1318 { 1319 Query: "INSERT", 1320 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 1321 }, 1322 { 1323 Id: []byte{0xca, 0xfe, 0xba, 0xbe}, 1324 Values: []*primitive.Value{primitive.NewValue([]byte{5, 6, 7, 8})}, 1325 }, 1326 }, 1327 }, 1328 nil, 1329 }, 1330 { 1331 "batch with custom options", 1332 []byte{ 1333 byte(primitive.BatchTypeUnlogged), 1334 0, 1, // children count 1335 0, // child 1 kind 1336 0, 0, 0, 6, I, N, S, E, R, T, // child 1 query 1337 0, 1, // child 1 values count 1338 0, 0, 0, 4, 1, 2, 3, 4, // child 1 value 1 1339 0, 6, // consistency 1340 0b0000_0000, // flags 1341 0b0000_0000, // flags 1342 0b0000_0000, // flags 1343 0b1011_0000, // flags => 0x10 (serial) | 0x20 (timestamp) | 0x80 (keyspace) 1344 0, 9, // serial consistency 1345 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 1346 0, 3, k, s, _1, // keyspace 1347 }, 1348 &Batch{ 1349 Type: primitive.BatchTypeUnlogged, 1350 Children: []*BatchChild{ 1351 { 1352 Query: "INSERT", 1353 Values: []*primitive.Value{primitive.NewValue([]byte{1, 2, 3, 4})}, 1354 }, 1355 }, 1356 Consistency: primitive.ConsistencyLevelLocalQuorum, 1357 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1358 DefaultTimestamp: int64Ptr(123), 1359 Keyspace: "ks1", 1360 }, 1361 nil, 1362 }, 1363 } 1364 for _, tt := range tests { 1365 t.Run(tt.name, func(t *testing.T) { 1366 source := bytes.NewBuffer(tt.input) 1367 actual, err := codec.Decode(source, primitive.ProtocolVersionDse2) 1368 assert.Equal(t, tt.expected, actual) 1369 assert.Equal(t, tt.err, err) 1370 }) 1371 } 1372 }) 1373 }