github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/message/query_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 TestQuery_DeepCopy(t *testing.T) { 28 msg := &Query{ 29 Query: "query", 30 Options: &QueryOptions{ 31 Consistency: primitive.ConsistencyLevelAll, 32 PositionalValues: []*primitive.Value{ 33 { 34 Type: primitive.ValueTypeRegular, 35 Contents: []byte{0x11}, 36 }, 37 }, 38 NamedValues: map[string]*primitive.Value{ 39 "1": { 40 Type: primitive.ValueTypeUnset, 41 Contents: []byte{0x21}, 42 }, 43 }, 44 SkipMetadata: false, 45 PageSize: 5, 46 PageSizeInBytes: false, 47 PagingState: []byte{0x33}, 48 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 49 DefaultTimestamp: int64Ptr(1), 50 Keyspace: "ks1", 51 NowInSeconds: int32Ptr(3), 52 ContinuousPagingOptions: &ContinuousPagingOptions{ 53 MaxPages: 5, 54 PagesPerSecond: 2, 55 NextPages: 3, 56 }, 57 }, 58 } 59 60 cloned := msg.DeepCopy() 61 assert.Equal(t, msg, cloned) 62 63 cloned.Query = "query 2" 64 cloned.Options = &QueryOptions{ 65 Consistency: primitive.ConsistencyLevelLocalOne, 66 PositionalValues: []*primitive.Value{ 67 { 68 Type: primitive.ValueTypeUnset, 69 Contents: []byte{0x21}, 70 }, 71 }, 72 NamedValues: map[string]*primitive.Value{ 73 "1": { 74 Type: primitive.ValueTypeNull, 75 Contents: []byte{0x31}, 76 }, 77 }, 78 SkipMetadata: true, 79 PageSize: 4, 80 PageSizeInBytes: true, 81 PagingState: []byte{0x23}, 82 SerialConsistency: nil, 83 DefaultTimestamp: int64Ptr(3), 84 Keyspace: "ks2", 85 NowInSeconds: nil, 86 ContinuousPagingOptions: &ContinuousPagingOptions{ 87 MaxPages: 6, 88 PagesPerSecond: 3, 89 NextPages: 4, 90 }, 91 } 92 93 assert.Equal(t, "query", msg.Query) 94 assert.Equal(t, primitive.ConsistencyLevelAll, msg.Options.Consistency) 95 assert.Equal(t, primitive.ValueTypeRegular, msg.Options.PositionalValues[0].Type) 96 assert.Equal(t, []byte{0x11}, msg.Options.PositionalValues[0].Contents) 97 assert.Equal(t, primitive.ValueTypeUnset, msg.Options.NamedValues["1"].Type) 98 assert.Equal(t, []byte{0x21}, msg.Options.NamedValues["1"].Contents) 99 assert.False(t, msg.Options.SkipMetadata) 100 assert.EqualValues(t, 5, msg.Options.PageSize) 101 assert.False(t, msg.Options.PageSizeInBytes) 102 assert.Equal(t, []byte{0x33}, msg.Options.PagingState) 103 assert.Equal(t, primitive.ConsistencyLevelLocalSerial, *msg.Options.SerialConsistency) 104 assert.EqualValues(t, 1, *msg.Options.DefaultTimestamp) 105 assert.Equal(t, "ks1", msg.Options.Keyspace) 106 assert.EqualValues(t, 3, *msg.Options.NowInSeconds) 107 assert.EqualValues(t, 5, msg.Options.ContinuousPagingOptions.MaxPages) 108 assert.EqualValues(t, 2, msg.Options.ContinuousPagingOptions.PagesPerSecond) 109 assert.EqualValues(t, 3, msg.Options.ContinuousPagingOptions.NextPages) 110 111 assert.NotEqual(t, msg, cloned) 112 113 assert.Equal(t, "query 2", cloned.Query) 114 assert.Equal(t, primitive.ConsistencyLevelLocalOne, cloned.Options.Consistency) 115 assert.Equal(t, primitive.ValueTypeUnset, cloned.Options.PositionalValues[0].Type) 116 assert.Equal(t, []byte{0x21}, cloned.Options.PositionalValues[0].Contents) 117 assert.Equal(t, primitive.ValueTypeNull, cloned.Options.NamedValues["1"].Type) 118 assert.Equal(t, []byte{0x31}, cloned.Options.NamedValues["1"].Contents) 119 assert.True(t, cloned.Options.SkipMetadata) 120 assert.EqualValues(t, 4, cloned.Options.PageSize) 121 assert.True(t, cloned.Options.PageSizeInBytes) 122 assert.Equal(t, []byte{0x23}, cloned.Options.PagingState) 123 assert.Nil(t, cloned.Options.SerialConsistency) 124 assert.EqualValues(t, 3, *cloned.Options.DefaultTimestamp) 125 assert.Equal(t, "ks2", cloned.Options.Keyspace) 126 assert.Nil(t, cloned.Options.NowInSeconds) 127 assert.EqualValues(t, 6, cloned.Options.ContinuousPagingOptions.MaxPages) 128 assert.EqualValues(t, 3, cloned.Options.ContinuousPagingOptions.PagesPerSecond) 129 assert.EqualValues(t, 4, cloned.Options.ContinuousPagingOptions.NextPages) 130 } 131 132 func TestQueryCodec_Encode(t *testing.T) { 133 codec := &queryCodec{} 134 // tests for version 2 135 t.Run(primitive.ProtocolVersion2.String(), func(t *testing.T) { 136 tests := []encodeTestCase{ 137 { 138 "query with default options", 139 &Query{ 140 Query: "SELECT", 141 Options: &QueryOptions{}, 142 }, 143 []byte{ 144 0, 0, 0, 6, S, E, L, E, C, T, 145 0, 0, // consistency level 146 0, // flags 147 }, 148 nil, 149 }, 150 { 151 "query with custom options and no values", 152 &Query{ 153 Query: "SELECT", 154 Options: &QueryOptions{ 155 Consistency: primitive.ConsistencyLevelLocalQuorum, 156 SkipMetadata: true, 157 PageSize: 100, 158 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 159 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 160 DefaultTimestamp: int64Ptr(123), 161 }, 162 }, 163 []byte{ 164 0, 0, 0, 6, S, E, L, E, C, T, 165 0, 6, // consistency level 166 0b0011_1110, // flags 167 0, 0, 0, 100, // page size 168 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 169 0, 9, // serial consistency level 170 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 171 }, 172 nil, 173 }, 174 { 175 "query with positional values", 176 &Query{ 177 Query: "SELECT", 178 Options: &QueryOptions{ 179 PositionalValues: []*primitive.Value{ 180 { 181 Type: primitive.ValueTypeRegular, 182 Contents: []byte{h, e, l, l, o}, 183 }, 184 { 185 Type: primitive.ValueTypeNull, 186 }, 187 }, 188 }, 189 }, 190 []byte{ 191 0, 0, 0, 6, S, E, L, E, C, T, 192 0, 0, // consistency level 193 0b0000_0001, // flags 194 0, 2, // values length 195 0, 0, 0, 5, h, e, l, l, o, // value 1 196 0xff, 0xff, 0xff, 0xff, // value 2 197 }, 198 nil, 199 }, 200 { 201 "query with named values", 202 &Query{ 203 Query: "SELECT", 204 Options: &QueryOptions{ 205 NamedValues: map[string]*primitive.Value{ 206 "col1": { 207 Type: primitive.ValueTypeRegular, 208 Contents: []byte{h, e, l, l, o}, 209 }, 210 }, 211 }, 212 }, 213 []byte{ 214 0, 0, 0, 6, S, E, L, E, C, T, 215 0, 0, // consistency level 216 0b0100_0001, // flags 217 0, 1, // values length 218 0, 4, c, o, l, _1, // name 1 219 0, 0, 0, 5, h, e, l, l, o, // value 1 220 }, 221 nil, 222 }, 223 { 224 "query with empty query string", 225 &Query{}, 226 []byte{ 227 0, 0, 0, 0, // empty query 228 0, 0, // consistency level 229 0, // flags 230 }, 231 nil, 232 }, 233 { 234 "not a query", 235 &Options{}, 236 nil, 237 errors.New("expected *message.Query, got *message.Options"), 238 }, 239 } 240 for _, tt := range tests { 241 t.Run(tt.name, func(t *testing.T) { 242 dest := &bytes.Buffer{} 243 err := codec.Encode(tt.input, dest, primitive.ProtocolVersion2) 244 assert.Equal(t, tt.expected, dest.Bytes()) 245 assert.Equal(t, tt.err, err) 246 }) 247 } 248 }) 249 // tests for version 3 250 t.Run(primitive.ProtocolVersion3.String(), func(t *testing.T) { 251 tests := []encodeTestCase{ 252 { 253 "query with default options", 254 &Query{ 255 Query: "SELECT", 256 Options: &QueryOptions{}, 257 }, 258 []byte{ 259 0, 0, 0, 6, S, E, L, E, C, T, 260 0, 0, // consistency level 261 0, // flags 262 }, 263 nil, 264 }, 265 { 266 "query with custom options and no values", 267 &Query{ 268 Query: "SELECT", 269 Options: &QueryOptions{ 270 Consistency: primitive.ConsistencyLevelLocalQuorum, 271 SkipMetadata: true, 272 PageSize: 100, 273 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 274 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 275 DefaultTimestamp: int64Ptr(123), 276 }, 277 }, 278 []byte{ 279 0, 0, 0, 6, S, E, L, E, C, T, 280 0, 6, // consistency level 281 0b0011_1110, // flags 282 0, 0, 0, 100, // page size 283 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 284 0, 9, // serial consistency level 285 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 286 }, 287 nil, 288 }, 289 { 290 "query with positional values", 291 &Query{ 292 Query: "SELECT", 293 Options: &QueryOptions{ 294 PositionalValues: []*primitive.Value{ 295 { 296 Type: primitive.ValueTypeRegular, 297 Contents: []byte{h, e, l, l, o}, 298 }, 299 { 300 Type: primitive.ValueTypeNull, 301 }, 302 }, 303 }, 304 }, 305 []byte{ 306 0, 0, 0, 6, S, E, L, E, C, T, 307 0, 0, // consistency level 308 0b0000_0001, // flags 309 0, 2, // values length 310 0, 0, 0, 5, h, e, l, l, o, // value 1 311 0xff, 0xff, 0xff, 0xff, // value 2 312 }, 313 nil, 314 }, 315 { 316 "query with named values", 317 &Query{ 318 Query: "SELECT", 319 Options: &QueryOptions{ 320 NamedValues: map[string]*primitive.Value{ 321 "col1": { 322 Type: primitive.ValueTypeRegular, 323 Contents: []byte{h, e, l, l, o}, 324 }, 325 }, 326 }, 327 }, 328 []byte{ 329 0, 0, 0, 6, S, E, L, E, C, T, 330 0, 0, // consistency level 331 0b0100_0001, // flags 332 0, 1, // values length 333 0, 4, c, o, l, _1, // name 1 334 0, 0, 0, 5, h, e, l, l, o, // value 1 335 }, 336 nil, 337 }, 338 { 339 "query with empty query string", 340 &Query{}, 341 []byte{ 342 0, 0, 0, 0, // empty query 343 0, 0, // consistency level 344 0, // flags 345 }, 346 nil, 347 }, 348 { 349 "not a query", 350 &Options{}, 351 nil, 352 errors.New("expected *message.Query, got *message.Options"), 353 }, 354 } 355 for _, tt := range tests { 356 t.Run(tt.name, func(t *testing.T) { 357 dest := &bytes.Buffer{} 358 err := codec.Encode(tt.input, dest, primitive.ProtocolVersion3) 359 assert.Equal(t, tt.expected, dest.Bytes()) 360 assert.Equal(t, tt.err, err) 361 }) 362 } 363 }) 364 // tests for version = 4 365 t.Run(primitive.ProtocolVersion4.String(), func(t *testing.T) { 366 tests := []struct { 367 name string 368 input Message 369 expected []byte 370 err error 371 }{ 372 { 373 "query with default options", 374 &Query{ 375 Query: "SELECT", 376 Options: &QueryOptions{}, 377 }, 378 []byte{ 379 0, 0, 0, 6, S, E, L, E, C, T, 380 0, 0, // consistency level 381 0, // flags 382 }, 383 nil, 384 }, 385 { 386 "query with custom options and no values", 387 &Query{ 388 Query: "SELECT", 389 Options: &QueryOptions{ 390 Consistency: primitive.ConsistencyLevelLocalQuorum, 391 SkipMetadata: true, 392 PageSize: 100, 393 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 394 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 395 DefaultTimestamp: int64Ptr(123), 396 }, 397 }, 398 []byte{ 399 0, 0, 0, 6, S, E, L, E, C, T, 400 0, 6, // consistency level 401 0b0011_1110, // flags 402 0, 0, 0, 100, // page size 403 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 404 0, 9, // serial consistency level 405 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 406 }, 407 nil, 408 }, 409 { 410 "query with positional values", 411 &Query{ 412 Query: "SELECT", 413 Options: &QueryOptions{ 414 PositionalValues: []*primitive.Value{ 415 { 416 Type: primitive.ValueTypeRegular, 417 Contents: []byte{h, e, l, l, o}, 418 }, 419 { 420 Type: primitive.ValueTypeNull, 421 }, 422 { 423 Type: primitive.ValueTypeUnset, 424 }, 425 }, 426 }, 427 }, 428 []byte{ 429 0, 0, 0, 6, S, E, L, E, C, T, 430 0, 0, // consistency level 431 0b0000_0001, // flags 432 0, 3, // values length 433 0, 0, 0, 5, h, e, l, l, o, // value 1 434 0xff, 0xff, 0xff, 0xff, // value 2 435 0xff, 0xff, 0xff, 0xfe, // value 3 436 }, 437 nil, 438 }, 439 { 440 "query with named values", 441 &Query{ 442 Query: "SELECT", 443 Options: &QueryOptions{ 444 NamedValues: map[string]*primitive.Value{ 445 "col1": { 446 Type: primitive.ValueTypeRegular, 447 Contents: []byte{h, e, l, l, o}, 448 }, 449 }, 450 }, 451 }, 452 []byte{ 453 0, 0, 0, 6, S, E, L, E, C, T, 454 0, 0, // consistency level 455 0b0100_0001, // flags 456 0, 1, // values length 457 0, 4, c, o, l, _1, // name 1 458 0, 0, 0, 5, h, e, l, l, o, // value 1 459 }, 460 nil, 461 }, 462 { 463 "query with empty query string", 464 &Query{}, 465 []byte{ 466 0, 0, 0, 0, // empty query 467 0, 0, // consistency level 468 0, // flags 469 }, 470 nil, 471 }, 472 { 473 "not a query", 474 &Options{}, 475 nil, 476 errors.New("expected *message.Query, got *message.Options"), 477 }, 478 } 479 for _, tt := range tests { 480 t.Run(tt.name, func(t *testing.T) { 481 dest := &bytes.Buffer{} 482 err := codec.Encode(tt.input, dest, primitive.ProtocolVersion4) 483 assert.Equal(t, tt.expected, dest.Bytes()) 484 assert.Equal(t, tt.err, err) 485 }) 486 } 487 }) 488 // tests for version = 5 489 t.Run(primitive.ProtocolVersion5.String(), func(t *testing.T) { 490 tests := []encodeTestCase{ 491 { 492 "query with keyspace and now-in-seconds", 493 &Query{ 494 Query: "SELECT", 495 Options: &QueryOptions{ 496 Keyspace: "ks1", 497 NowInSeconds: int32Ptr(123), 498 }, 499 }, 500 []byte{ 501 0, 0, 0, 6, S, E, L, E, C, T, 502 0, 0, // consistency level 503 0b0000_0000, // flags 504 0b0000_0000, // flags 505 0b0000_0001, // flags (keyspace) 506 0b1000_0000, // flags (now in seconds) 507 0, 3, k, s, _1, // keyspace 508 0, 0, 0, 123, // now in seconds 509 }, 510 nil, 511 }, 512 { 513 "query with positional values, keyspace and now-in-seconds", 514 &Query{ 515 Query: "SELECT", 516 Options: &QueryOptions{ 517 Keyspace: "ks1", 518 NowInSeconds: int32Ptr(123), 519 PositionalValues: []*primitive.Value{ 520 { 521 Type: primitive.ValueTypeRegular, 522 Contents: []byte{h, e, l, l, o}, 523 }, 524 { 525 Type: primitive.ValueTypeNull, 526 }, 527 { 528 Type: primitive.ValueTypeUnset, 529 }, 530 }, 531 }, 532 }, 533 []byte{ 534 0, 0, 0, 6, S, E, L, E, C, T, 535 0, 0, // consistency level 536 0b0000_0000, // flags 537 0b0000_0000, // flags 538 0b0000_0001, // flags 539 0b1000_0001, // flags 540 0, 3, // values length 541 0, 0, 0, 5, h, e, l, l, o, // value 1 542 0xff, 0xff, 0xff, 0xff, // value 2 543 0xff, 0xff, 0xff, 0xfe, // value 3 544 0, 3, k, s, _1, // keyspace 545 0, 0, 0, 123, // now in seconds 546 }, 547 nil, 548 }, 549 } 550 for _, tt := range tests { 551 t.Run(tt.name, func(t *testing.T) { 552 dest := &bytes.Buffer{} 553 err := codec.Encode(tt.input, dest, primitive.ProtocolVersion5) 554 assert.Equal(t, tt.expected, dest.Bytes()) 555 assert.Equal(t, tt.err, err) 556 }) 557 } 558 }) 559 // tests for version = DSE v1 560 t.Run(primitive.ProtocolVersionDse1.String(), func(t *testing.T) { 561 tests := []struct { 562 name string 563 input Message 564 expected []byte 565 err error 566 }{ 567 { 568 "query with default options", 569 &Query{ 570 Query: "SELECT", 571 Options: &QueryOptions{}, 572 }, 573 []byte{ 574 0, 0, 0, 6, S, E, L, E, C, T, 575 0, 0, // consistency level 576 0, 0, 0, 0, // flags 577 }, 578 nil, 579 }, 580 { 581 "query with custom options and no values", 582 &Query{ 583 Query: "SELECT", 584 Options: &QueryOptions{ 585 Consistency: primitive.ConsistencyLevelLocalQuorum, 586 SkipMetadata: true, 587 PageSize: 100, 588 PageSizeInBytes: true, 589 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 590 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 591 DefaultTimestamp: int64Ptr(123), 592 ContinuousPagingOptions: &ContinuousPagingOptions{MaxPages: 50, PagesPerSecond: 10}, 593 }, 594 }, 595 []byte{ 596 0, 0, 0, 6, S, E, L, E, C, T, 597 0, 6, // consistency level 598 0b1100_0000, 0, 0, 0b0011_1110, // flags 599 0, 0, 0, 100, // page size 600 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 601 0, 9, // serial consistency level 602 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 603 0, 0, 0, 50, // max pages 604 0, 0, 0, 10, // pages per sec 605 }, 606 nil, 607 }, 608 { 609 "query with positional values", 610 &Query{ 611 Query: "SELECT", 612 Options: &QueryOptions{ 613 PositionalValues: []*primitive.Value{ 614 { 615 Type: primitive.ValueTypeRegular, 616 Contents: []byte{h, e, l, l, o}, 617 }, 618 { 619 Type: primitive.ValueTypeNull, 620 }, 621 { 622 Type: primitive.ValueTypeUnset, 623 }, 624 }, 625 }, 626 }, 627 []byte{ 628 0, 0, 0, 6, S, E, L, E, C, T, 629 0, 0, // consistency level 630 0, 0, 0, 0b0000_0001, // flags 631 0, 3, // values length 632 0, 0, 0, 5, h, e, l, l, o, // value 1 633 0xff, 0xff, 0xff, 0xff, // value 2 634 0xff, 0xff, 0xff, 0xfe, // value 3 635 }, 636 nil, 637 }, 638 { 639 "query with named values", 640 &Query{ 641 Query: "SELECT", 642 Options: &QueryOptions{ 643 NamedValues: map[string]*primitive.Value{ 644 "col1": { 645 Type: primitive.ValueTypeRegular, 646 Contents: []byte{h, e, l, l, o}, 647 }, 648 }, 649 }, 650 }, 651 []byte{ 652 0, 0, 0, 6, S, E, L, E, C, T, 653 0, 0, // consistency level 654 0, 0, 0, 0b0100_0001, // flags 655 0, 1, // values length 656 0, 4, c, o, l, _1, // name 1 657 0, 0, 0, 5, h, e, l, l, o, // value 1 658 }, 659 nil, 660 }, 661 { 662 "query with empty query string", 663 &Query{}, 664 []byte{ 665 0, 0, 0, 0, // empty query 666 0, 0, // consistency level 667 0, 0, 0, 0, // flags 668 }, 669 nil, 670 }, 671 { 672 "not a query", 673 &Options{}, 674 nil, 675 errors.New("expected *message.Query, got *message.Options"), 676 }, 677 } 678 for _, tt := range tests { 679 t.Run(tt.name, func(t *testing.T) { 680 dest := &bytes.Buffer{} 681 err := codec.Encode(tt.input, dest, primitive.ProtocolVersionDse1) 682 assert.Equal(t, tt.expected, dest.Bytes()) 683 assert.Equal(t, tt.err, err) 684 }) 685 } 686 }) 687 // tests for version = DSE v2 688 t.Run(primitive.ProtocolVersionDse2.String(), func(t *testing.T) { 689 tests := []encodeTestCase{ 690 { 691 "query with keyspace and continuous options", 692 &Query{ 693 Query: "SELECT", 694 Options: &QueryOptions{ 695 Keyspace: "ks1", 696 ContinuousPagingOptions: &ContinuousPagingOptions{MaxPages: 50, PagesPerSecond: 10, NextPages: 20}, 697 }, 698 }, 699 []byte{ 700 0, 0, 0, 6, S, E, L, E, C, T, 701 0, 0, // consistency level 702 0b1000_0000, // flags (cont. paging) 703 0b0000_0000, // flags 704 0b0000_0000, // flags 705 0b1000_0000, // flags (keyspace) 706 0, 3, k, s, _1, // keyspace 707 0, 0, 0, 50, // max pages 708 0, 0, 0, 10, // pages per sec 709 0, 0, 0, 20, // next pages 710 }, 711 nil, 712 }, 713 { 714 "query with custom options and no values", 715 &Query{ 716 Query: "SELECT", 717 Options: &QueryOptions{ 718 Consistency: primitive.ConsistencyLevelLocalQuorum, 719 SkipMetadata: true, 720 PageSize: 100, 721 PageSizeInBytes: true, 722 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 723 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 724 DefaultTimestamp: int64Ptr(123), 725 ContinuousPagingOptions: &ContinuousPagingOptions{MaxPages: 50, PagesPerSecond: 10, NextPages: 20}, 726 }, 727 }, 728 []byte{ 729 0, 0, 0, 6, S, E, L, E, C, T, 730 0, 6, // consistency level 731 0b1100_0000, 0, 0, 0b0011_1110, // flags 732 0, 0, 0, 100, // page size 733 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 734 0, 9, // serial consistency level 735 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 736 0, 0, 0, 50, // max pages 737 0, 0, 0, 10, // pages per sec 738 0, 0, 0, 20, // next pages 739 }, 740 nil, 741 }, 742 { 743 "query with positional values and keyspace", 744 &Query{ 745 Query: "SELECT", 746 Options: &QueryOptions{ 747 Keyspace: "ks1", 748 PositionalValues: []*primitive.Value{ 749 { 750 Type: primitive.ValueTypeRegular, 751 Contents: []byte{h, e, l, l, o}, 752 }, 753 { 754 Type: primitive.ValueTypeNull, 755 }, 756 { 757 Type: primitive.ValueTypeUnset, 758 }, 759 }, 760 }, 761 }, 762 []byte{ 763 0, 0, 0, 6, S, E, L, E, C, T, 764 0, 0, // consistency level 765 0b0000_0000, // flags 766 0b0000_0000, // flags 767 0b0000_0000, // flags 768 0b1000_0001, // flags (keyspace | values) 769 0, 3, // values length 770 0, 0, 0, 5, h, e, l, l, o, // value 1 771 0xff, 0xff, 0xff, 0xff, // value 2 772 0xff, 0xff, 0xff, 0xfe, // value 3 773 0, 3, k, s, _1, // keyspace 774 }, 775 nil, 776 }, 777 } 778 for _, tt := range tests { 779 t.Run(tt.name, func(t *testing.T) { 780 dest := &bytes.Buffer{} 781 err := codec.Encode(tt.input, dest, primitive.ProtocolVersionDse2) 782 assert.Equal(t, tt.expected, dest.Bytes()) 783 assert.Equal(t, tt.err, err) 784 }) 785 } 786 }) 787 } 788 789 func TestQueryCodec_EncodedLength(t *testing.T) { 790 codec := &queryCodec{} 791 // tests for version 2 792 t.Run(primitive.ProtocolVersion2.String(), func(t *testing.T) { 793 tests := []encodedLengthTestCase{ 794 { 795 "query with default options", 796 &Query{ 797 Query: "SELECT", 798 Options: &QueryOptions{}, 799 }, 800 primitive.LengthOfLongString("SELECT") + 801 primitive.LengthOfShort + // consistency 802 primitive.LengthOfByte, // flags 803 nil, 804 }, 805 { 806 "query with custom options and no values", 807 &Query{ 808 Query: "SELECT", 809 Options: &QueryOptions{ 810 Consistency: primitive.ConsistencyLevelLocalQuorum, 811 SkipMetadata: true, 812 PageSize: 100, 813 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 814 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 815 DefaultTimestamp: int64Ptr(123), 816 }, 817 }, 818 primitive.LengthOfLongString("SELECT") + 819 primitive.LengthOfShort + // consistency 820 primitive.LengthOfByte + // flags 821 primitive.LengthOfInt + // page size 822 primitive.LengthOfBytes([]byte{0xca, 0xfe, 0xba, 0xbe}) + // paging state 823 primitive.LengthOfShort + // serial consistency 824 primitive.LengthOfLong, // default timestamp 825 nil, 826 }, 827 { 828 "query with positional values", 829 &Query{ 830 Query: "SELECT", 831 Options: &QueryOptions{ 832 PositionalValues: []*primitive.Value{ 833 { 834 Type: primitive.ValueTypeRegular, 835 Contents: []byte{h, e, l, l, o}, 836 }, 837 { 838 Type: primitive.ValueTypeNull, 839 }, 840 }, 841 }, 842 }, 843 primitive.LengthOfLongString("SELECT") + 844 primitive.LengthOfShort + // consistency 845 primitive.LengthOfByte + // flags 846 primitive.LengthOfShort + // values length 847 primitive.LengthOfBytes([]byte{h, e, l, l, o}) + // value 1 848 primitive.LengthOfInt, // value 2 849 nil, 850 }, 851 { 852 "query with named values", 853 &Query{ 854 Query: "SELECT", 855 Options: &QueryOptions{ 856 NamedValues: map[string]*primitive.Value{ 857 "col1": { 858 Type: primitive.ValueTypeRegular, 859 Contents: []byte{h, e, l, l, o}, 860 }, 861 }, 862 }, 863 }, 864 primitive.LengthOfLongString("SELECT") + 865 primitive.LengthOfShort + // consistency 866 primitive.LengthOfByte + // flags 867 primitive.LengthOfShort + // values length 868 primitive.LengthOfString("col1") + // name 1 869 primitive.LengthOfBytes([]byte{h, e, l, l, o}), // value 1 870 nil, 871 }, 872 { 873 "not a query", 874 &Options{}, 875 -1, 876 errors.New("expected *message.Query, got *message.Options"), 877 }, 878 } 879 for _, tt := range tests { 880 t.Run(tt.name, func(t *testing.T) { 881 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersion2) 882 assert.Equal(t, tt.expected, actual) 883 assert.Equal(t, tt.err, err) 884 }) 885 } 886 }) 887 // tests for version 3 888 t.Run(primitive.ProtocolVersion3.String(), func(t *testing.T) { 889 tests := []encodedLengthTestCase{ 890 { 891 "query with default options", 892 &Query{ 893 Query: "SELECT", 894 Options: &QueryOptions{}, 895 }, 896 primitive.LengthOfLongString("SELECT") + 897 primitive.LengthOfShort + // consistency 898 primitive.LengthOfByte, // flags 899 nil, 900 }, 901 { 902 "query with custom options and no values", 903 &Query{ 904 Query: "SELECT", 905 Options: &QueryOptions{ 906 Consistency: primitive.ConsistencyLevelLocalQuorum, 907 SkipMetadata: true, 908 PageSize: 100, 909 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 910 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 911 DefaultTimestamp: int64Ptr(123), 912 }, 913 }, 914 primitive.LengthOfLongString("SELECT") + 915 primitive.LengthOfShort + // consistency 916 primitive.LengthOfByte + // flags 917 primitive.LengthOfInt + // page size 918 primitive.LengthOfBytes([]byte{0xca, 0xfe, 0xba, 0xbe}) + // paging state 919 primitive.LengthOfShort + // serial consistency 920 primitive.LengthOfLong, // default timestamp 921 nil, 922 }, 923 { 924 "query with positional values", 925 &Query{ 926 Query: "SELECT", 927 Options: &QueryOptions{ 928 PositionalValues: []*primitive.Value{ 929 { 930 Type: primitive.ValueTypeRegular, 931 Contents: []byte{h, e, l, l, o}, 932 }, 933 { 934 Type: primitive.ValueTypeNull, 935 }, 936 }, 937 }, 938 }, 939 primitive.LengthOfLongString("SELECT") + 940 primitive.LengthOfShort + // consistency 941 primitive.LengthOfByte + // flags 942 primitive.LengthOfShort + // values length 943 primitive.LengthOfBytes([]byte{h, e, l, l, o}) + // value 1 944 primitive.LengthOfInt, // value 2 945 nil, 946 }, 947 { 948 "query with named values", 949 &Query{ 950 Query: "SELECT", 951 Options: &QueryOptions{ 952 NamedValues: map[string]*primitive.Value{ 953 "col1": { 954 Type: primitive.ValueTypeRegular, 955 Contents: []byte{h, e, l, l, o}, 956 }, 957 }, 958 }, 959 }, 960 primitive.LengthOfLongString("SELECT") + 961 primitive.LengthOfShort + // consistency 962 primitive.LengthOfByte + // flags 963 primitive.LengthOfShort + // values length 964 primitive.LengthOfString("col1") + // name 1 965 primitive.LengthOfBytes([]byte{h, e, l, l, o}), // value 1 966 nil, 967 }, 968 { 969 "not a query", 970 &Options{}, 971 -1, 972 errors.New("expected *message.Query, got *message.Options"), 973 }, 974 } 975 for _, tt := range tests { 976 t.Run(tt.name, func(t *testing.T) { 977 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersion3) 978 assert.Equal(t, tt.expected, actual) 979 assert.Equal(t, tt.err, err) 980 }) 981 } 982 }) 983 // tests for version = 4 984 t.Run(primitive.ProtocolVersion4.String(), func(t *testing.T) { 985 tests := []struct { 986 name string 987 input Message 988 expected int 989 err error 990 }{ 991 { 992 "query with default options", 993 &Query{ 994 Query: "SELECT", 995 Options: &QueryOptions{}, 996 }, 997 primitive.LengthOfLongString("SELECT") + 998 primitive.LengthOfShort + // consistency 999 primitive.LengthOfByte, // flags 1000 nil, 1001 }, 1002 { 1003 "query with custom options and no values", 1004 &Query{ 1005 Query: "SELECT", 1006 Options: &QueryOptions{ 1007 Consistency: primitive.ConsistencyLevelLocalQuorum, 1008 SkipMetadata: true, 1009 PageSize: 100, 1010 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 1011 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1012 DefaultTimestamp: int64Ptr(123), 1013 }, 1014 }, 1015 primitive.LengthOfLongString("SELECT") + 1016 primitive.LengthOfShort + // consistency 1017 primitive.LengthOfByte + // flags 1018 primitive.LengthOfInt + // page size 1019 primitive.LengthOfBytes([]byte{0xca, 0xfe, 0xba, 0xbe}) + // paging state 1020 primitive.LengthOfShort + // serial consistency 1021 primitive.LengthOfLong, // default timestamp 1022 nil, 1023 }, 1024 { 1025 "query with positional values", 1026 &Query{ 1027 Query: "SELECT", 1028 Options: &QueryOptions{ 1029 PositionalValues: []*primitive.Value{ 1030 { 1031 Type: primitive.ValueTypeRegular, 1032 Contents: []byte{h, e, l, l, o}, 1033 }, 1034 { 1035 Type: primitive.ValueTypeNull, 1036 }, 1037 { 1038 Type: primitive.ValueTypeUnset, 1039 }, 1040 }, 1041 }, 1042 }, 1043 primitive.LengthOfLongString("SELECT") + 1044 primitive.LengthOfShort + // consistency 1045 primitive.LengthOfByte + // flags 1046 primitive.LengthOfShort + // values length 1047 primitive.LengthOfBytes([]byte{h, e, l, l, o}) + // value 1 1048 primitive.LengthOfInt + // value 2 1049 primitive.LengthOfInt, // value 3 1050 nil, 1051 }, 1052 { 1053 "query with named values", 1054 &Query{ 1055 Query: "SELECT", 1056 Options: &QueryOptions{ 1057 NamedValues: map[string]*primitive.Value{ 1058 "col1": { 1059 Type: primitive.ValueTypeRegular, 1060 Contents: []byte{h, e, l, l, o}, 1061 }, 1062 }, 1063 }, 1064 }, 1065 primitive.LengthOfLongString("SELECT") + 1066 primitive.LengthOfShort + // consistency 1067 primitive.LengthOfByte + // flags 1068 primitive.LengthOfShort + // values length 1069 primitive.LengthOfString("col1") + // name 1 1070 primitive.LengthOfBytes([]byte{h, e, l, l, o}), // value 1 1071 nil, 1072 }, 1073 { 1074 "not a query", 1075 &Options{}, 1076 -1, 1077 errors.New("expected *message.Query, got *message.Options"), 1078 }, 1079 } 1080 for _, tt := range tests { 1081 t.Run(tt.name, func(t *testing.T) { 1082 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersion4) 1083 assert.Equal(t, tt.expected, actual) 1084 assert.Equal(t, tt.err, err) 1085 }) 1086 } 1087 }) 1088 // tests for version = 5 1089 t.Run(primitive.ProtocolVersion5.String(), func(t *testing.T) { 1090 tests := []encodedLengthTestCase{ 1091 { 1092 "query with keyspace and now-in-seconds", 1093 &Query{ 1094 Query: "SELECT", 1095 Options: &QueryOptions{ 1096 Keyspace: "ks1", 1097 NowInSeconds: int32Ptr(123), 1098 }, 1099 }, 1100 primitive.LengthOfLongString("SELECT") + 1101 primitive.LengthOfShort + // consistency 1102 primitive.LengthOfInt + // flags 1103 primitive.LengthOfString("ks1") + // keyspace 1104 primitive.LengthOfInt, // new in seconds 1105 nil, 1106 }, 1107 { 1108 "query with positional values, keyspace and now-in-seconds", 1109 &Query{ 1110 Query: "SELECT", 1111 Options: &QueryOptions{ 1112 Keyspace: "ks1", 1113 NowInSeconds: int32Ptr(123), 1114 PositionalValues: []*primitive.Value{ 1115 { 1116 Type: primitive.ValueTypeRegular, 1117 Contents: []byte{h, e, l, l, o}, 1118 }, 1119 { 1120 Type: primitive.ValueTypeNull, 1121 }, 1122 { 1123 Type: primitive.ValueTypeUnset, 1124 }, 1125 }, 1126 }, 1127 }, 1128 primitive.LengthOfLongString("SELECT") + 1129 primitive.LengthOfShort + // consistency 1130 primitive.LengthOfInt + // flags 1131 primitive.LengthOfShort + // values length 1132 primitive.LengthOfBytes([]byte{h, e, l, l, o}) + // value 1 1133 primitive.LengthOfInt + // value 2 1134 primitive.LengthOfInt + // value 3 1135 primitive.LengthOfString("ks1") + // keyspace 1136 primitive.LengthOfInt, // new in seconds 1137 nil, 1138 }, 1139 } 1140 for _, tt := range tests { 1141 t.Run(tt.name, func(t *testing.T) { 1142 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersion5) 1143 assert.Equal(t, tt.expected, actual) 1144 assert.Equal(t, tt.err, err) 1145 }) 1146 } 1147 }) 1148 // tests for version = DSE v1 1149 t.Run(primitive.ProtocolVersionDse1.String(), func(t *testing.T) { 1150 tests := []struct { 1151 name string 1152 input Message 1153 expected int 1154 err error 1155 }{ 1156 { 1157 "query with default options", 1158 &Query{ 1159 Query: "SELECT", 1160 Options: &QueryOptions{}, 1161 }, 1162 primitive.LengthOfLongString("SELECT") + 1163 primitive.LengthOfShort + // consistency 1164 primitive.LengthOfInt, // flags 1165 nil, 1166 }, 1167 { 1168 "query with custom options and no values", 1169 &Query{ 1170 Query: "SELECT", 1171 Options: &QueryOptions{ 1172 Consistency: primitive.ConsistencyLevelLocalQuorum, 1173 SkipMetadata: true, 1174 PageSize: 100, 1175 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 1176 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1177 DefaultTimestamp: int64Ptr(123), 1178 ContinuousPagingOptions: &ContinuousPagingOptions{MaxPages: 50, PagesPerSecond: 10}, 1179 }, 1180 }, 1181 primitive.LengthOfLongString("SELECT") + 1182 primitive.LengthOfShort + // consistency 1183 primitive.LengthOfInt + // flags 1184 primitive.LengthOfInt + // page size 1185 primitive.LengthOfBytes([]byte{0xca, 0xfe, 0xba, 0xbe}) + // paging state 1186 primitive.LengthOfShort + // serial consistency 1187 primitive.LengthOfLong + // default timestamp 1188 primitive.LengthOfInt*2, // cont. paging options 1189 nil, 1190 }, 1191 { 1192 "query with positional values", 1193 &Query{ 1194 Query: "SELECT", 1195 Options: &QueryOptions{ 1196 PositionalValues: []*primitive.Value{ 1197 { 1198 Type: primitive.ValueTypeRegular, 1199 Contents: []byte{h, e, l, l, o}, 1200 }, 1201 { 1202 Type: primitive.ValueTypeNull, 1203 }, 1204 { 1205 Type: primitive.ValueTypeUnset, 1206 }, 1207 }, 1208 }, 1209 }, 1210 primitive.LengthOfLongString("SELECT") + 1211 primitive.LengthOfShort + // consistency 1212 primitive.LengthOfInt + // flags 1213 primitive.LengthOfShort + // values length 1214 primitive.LengthOfBytes([]byte{h, e, l, l, o}) + // value 1 1215 primitive.LengthOfInt + // value 2 1216 primitive.LengthOfInt, // value 3 1217 nil, 1218 }, 1219 { 1220 "query with named values", 1221 &Query{ 1222 Query: "SELECT", 1223 Options: &QueryOptions{ 1224 NamedValues: map[string]*primitive.Value{ 1225 "col1": { 1226 Type: primitive.ValueTypeRegular, 1227 Contents: []byte{h, e, l, l, o}, 1228 }, 1229 }, 1230 }, 1231 }, 1232 primitive.LengthOfLongString("SELECT") + 1233 primitive.LengthOfShort + // consistency 1234 primitive.LengthOfInt + // flags 1235 primitive.LengthOfShort + // values length 1236 primitive.LengthOfString("col1") + // name 1 1237 primitive.LengthOfBytes([]byte{h, e, l, l, o}), // value 1 1238 nil, 1239 }, 1240 { 1241 "not a query", 1242 &Options{}, 1243 -1, 1244 errors.New("expected *message.Query, got *message.Options"), 1245 }, 1246 } 1247 for _, tt := range tests { 1248 t.Run(tt.name, func(t *testing.T) { 1249 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersionDse1) 1250 assert.Equal(t, tt.expected, actual) 1251 assert.Equal(t, tt.err, err) 1252 }) 1253 } 1254 }) 1255 // tests for version = DSE v2 1256 t.Run(primitive.ProtocolVersionDse2.String(), func(t *testing.T) { 1257 tests := []encodedLengthTestCase{ 1258 { 1259 "query with keyspace", 1260 &Query{ 1261 Query: "SELECT", 1262 Options: &QueryOptions{ 1263 Keyspace: "ks1", 1264 ContinuousPagingOptions: &ContinuousPagingOptions{MaxPages: 50, PagesPerSecond: 10, NextPages: 20}, 1265 }, 1266 }, 1267 primitive.LengthOfLongString("SELECT") + 1268 primitive.LengthOfShort + // consistency 1269 primitive.LengthOfInt + // flags 1270 primitive.LengthOfString("ks1") + // keyspace 1271 primitive.LengthOfInt*3, // cont. paging options 1272 nil, 1273 }, 1274 { 1275 "query with positional values and keyspace", 1276 &Query{ 1277 Query: "SELECT", 1278 Options: &QueryOptions{ 1279 Keyspace: "ks1", 1280 PositionalValues: []*primitive.Value{ 1281 { 1282 Type: primitive.ValueTypeRegular, 1283 Contents: []byte{h, e, l, l, o}, 1284 }, 1285 { 1286 Type: primitive.ValueTypeNull, 1287 }, 1288 { 1289 Type: primitive.ValueTypeUnset, 1290 }, 1291 }, 1292 }, 1293 }, 1294 primitive.LengthOfLongString("SELECT") + 1295 primitive.LengthOfShort + // consistency 1296 primitive.LengthOfInt + // flags 1297 primitive.LengthOfShort + // values length 1298 primitive.LengthOfBytes([]byte{h, e, l, l, o}) + // value 1 1299 primitive.LengthOfInt + // value 2 1300 primitive.LengthOfInt + // value 3 1301 primitive.LengthOfString("ks1"), // keyspace 1302 nil, 1303 }, 1304 } 1305 for _, tt := range tests { 1306 t.Run(tt.name, func(t *testing.T) { 1307 actual, err := codec.EncodedLength(tt.input, primitive.ProtocolVersionDse2) 1308 assert.Equal(t, tt.expected, actual) 1309 assert.Equal(t, tt.err, err) 1310 }) 1311 } 1312 }) 1313 } 1314 1315 func TestQueryCodec_Decode(t *testing.T) { 1316 codec := &queryCodec{} 1317 // tests for version 2 1318 t.Run(primitive.ProtocolVersion2.String(), func(t *testing.T) { 1319 tests := []decodeTestCase{ 1320 { 1321 "query with default options", 1322 []byte{ 1323 0, 0, 0, 6, S, E, L, E, C, T, 1324 0, 0, // consistency level 1325 0, // flags 1326 }, 1327 &Query{ 1328 Query: "SELECT", 1329 Options: &QueryOptions{}, 1330 }, 1331 nil, 1332 }, 1333 { 1334 "query with custom options and no values", 1335 []byte{ 1336 0, 0, 0, 6, S, E, L, E, C, T, 1337 0, 6, // consistency level 1338 0b0011_1110, // flags 1339 0, 0, 0, 100, // page size 1340 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 1341 0, 9, // serial consistency level 1342 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 1343 }, 1344 &Query{ 1345 Query: "SELECT", 1346 Options: &QueryOptions{ 1347 Consistency: primitive.ConsistencyLevelLocalQuorum, 1348 SkipMetadata: true, 1349 PageSize: 100, 1350 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 1351 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1352 DefaultTimestamp: int64Ptr(123), 1353 }, 1354 }, 1355 nil, 1356 }, 1357 { 1358 "query with positional values", 1359 []byte{ 1360 0, 0, 0, 6, S, E, L, E, C, T, 1361 0, 0, // consistency level 1362 0b0000_0001, // flags 1363 0, 2, // values length 1364 0, 0, 0, 5, h, e, l, l, o, // value 1 1365 0xff, 0xff, 0xff, 0xff, // value 2 1366 }, 1367 &Query{ 1368 Query: "SELECT", 1369 Options: &QueryOptions{ 1370 PositionalValues: []*primitive.Value{ 1371 { 1372 Type: primitive.ValueTypeRegular, 1373 Contents: []byte{h, e, l, l, o}, 1374 }, 1375 { 1376 Type: primitive.ValueTypeNull, 1377 }, 1378 }, 1379 }, 1380 }, 1381 nil, 1382 }, 1383 { 1384 "query with named values", 1385 []byte{ 1386 0, 0, 0, 6, S, E, L, E, C, T, 1387 0, 0, // consistency level 1388 0b0100_0001, // flags 1389 0, 1, // values length 1390 0, 4, c, o, l, _1, // name 1 1391 0, 0, 0, 5, h, e, l, l, o, // value 1 1392 }, 1393 &Query{ 1394 Query: "SELECT", 1395 Options: &QueryOptions{ 1396 NamedValues: map[string]*primitive.Value{ 1397 "col1": { 1398 Type: primitive.ValueTypeRegular, 1399 Contents: []byte{h, e, l, l, o}, 1400 }, 1401 }, 1402 }, 1403 }, 1404 nil, 1405 }, 1406 { 1407 "query with empty query string", 1408 []byte{ 1409 0, 0, 0, 0, // empty query 1410 0, 0, // consistency level 1411 0, // flags 1412 }, 1413 &Query{ 1414 Query: "", 1415 Options: &QueryOptions{}, 1416 }, 1417 nil, 1418 }, 1419 } 1420 for _, tt := range tests { 1421 t.Run(tt.name, func(t *testing.T) { 1422 source := bytes.NewBuffer(tt.input) 1423 actual, err := codec.Decode(source, primitive.ProtocolVersion2) 1424 assert.Equal(t, tt.expected, actual) 1425 assert.Equal(t, tt.err, err) 1426 }) 1427 } 1428 }) 1429 // tests for version 3 1430 t.Run(primitive.ProtocolVersion3.String(), func(t *testing.T) { 1431 tests := []decodeTestCase{ 1432 { 1433 "query with default options", 1434 []byte{ 1435 0, 0, 0, 6, S, E, L, E, C, T, 1436 0, 0, // consistency level 1437 0, // flags 1438 }, 1439 &Query{ 1440 Query: "SELECT", 1441 Options: &QueryOptions{}, 1442 }, 1443 nil, 1444 }, 1445 { 1446 "query with custom options and no values", 1447 []byte{ 1448 0, 0, 0, 6, S, E, L, E, C, T, 1449 0, 6, // consistency level 1450 0b0011_1110, // flags 1451 0, 0, 0, 100, // page size 1452 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 1453 0, 9, // serial consistency level 1454 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 1455 }, 1456 &Query{ 1457 Query: "SELECT", 1458 Options: &QueryOptions{ 1459 Consistency: primitive.ConsistencyLevelLocalQuorum, 1460 SkipMetadata: true, 1461 PageSize: 100, 1462 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 1463 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1464 DefaultTimestamp: int64Ptr(123), 1465 }, 1466 }, 1467 nil, 1468 }, 1469 { 1470 "query with positional values", 1471 []byte{ 1472 0, 0, 0, 6, S, E, L, E, C, T, 1473 0, 0, // consistency level 1474 0b0000_0001, // flags 1475 0, 2, // values length 1476 0, 0, 0, 5, h, e, l, l, o, // value 1 1477 0xff, 0xff, 0xff, 0xff, // value 2 1478 }, 1479 &Query{ 1480 Query: "SELECT", 1481 Options: &QueryOptions{ 1482 PositionalValues: []*primitive.Value{ 1483 { 1484 Type: primitive.ValueTypeRegular, 1485 Contents: []byte{h, e, l, l, o}, 1486 }, 1487 { 1488 Type: primitive.ValueTypeNull, 1489 }, 1490 }, 1491 }, 1492 }, 1493 nil, 1494 }, 1495 { 1496 "query with named values", 1497 []byte{ 1498 0, 0, 0, 6, S, E, L, E, C, T, 1499 0, 0, // consistency level 1500 0b0100_0001, // flags 1501 0, 1, // values length 1502 0, 4, c, o, l, _1, // name 1 1503 0, 0, 0, 5, h, e, l, l, o, // value 1 1504 }, 1505 &Query{ 1506 Query: "SELECT", 1507 Options: &QueryOptions{ 1508 NamedValues: map[string]*primitive.Value{ 1509 "col1": { 1510 Type: primitive.ValueTypeRegular, 1511 Contents: []byte{h, e, l, l, o}, 1512 }, 1513 }, 1514 }, 1515 }, 1516 nil, 1517 }, 1518 { 1519 "query with empty query string", 1520 []byte{ 1521 0, 0, 0, 0, // empty query 1522 0, 0, // consistency level 1523 0, // flags 1524 }, 1525 &Query{ 1526 Query: "", 1527 Options: &QueryOptions{}, 1528 }, 1529 nil, 1530 }, 1531 } 1532 for _, tt := range tests { 1533 t.Run(tt.name, func(t *testing.T) { 1534 source := bytes.NewBuffer(tt.input) 1535 actual, err := codec.Decode(source, primitive.ProtocolVersion3) 1536 assert.Equal(t, tt.expected, actual) 1537 assert.Equal(t, tt.err, err) 1538 }) 1539 } 1540 }) 1541 // tests for version = 4 1542 t.Run(primitive.ProtocolVersion4.String(), func(t *testing.T) { 1543 tests := []struct { 1544 name string 1545 input []byte 1546 expected Message 1547 err error 1548 }{ 1549 { 1550 "query with default options", 1551 []byte{ 1552 0, 0, 0, 6, S, E, L, E, C, T, 1553 0, 0, // consistency level 1554 0, // flags 1555 }, 1556 &Query{ 1557 Query: "SELECT", 1558 Options: &QueryOptions{}, 1559 }, 1560 nil, 1561 }, 1562 { 1563 "query with custom options and no values", 1564 []byte{ 1565 0, 0, 0, 6, S, E, L, E, C, T, 1566 0, 6, // consistency level 1567 0b0011_1110, // flags 1568 0, 0, 0, 100, // page size 1569 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 1570 0, 9, // serial consistency level 1571 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 1572 }, 1573 &Query{ 1574 Query: "SELECT", 1575 Options: &QueryOptions{ 1576 Consistency: primitive.ConsistencyLevelLocalQuorum, 1577 SkipMetadata: true, 1578 PageSize: 100, 1579 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 1580 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1581 DefaultTimestamp: int64Ptr(123), 1582 }, 1583 }, 1584 nil, 1585 }, 1586 { 1587 "query with positional values", 1588 []byte{ 1589 0, 0, 0, 6, S, E, L, E, C, T, 1590 0, 0, // consistency level 1591 0b0000_0001, // flags 1592 0, 3, // values length 1593 0, 0, 0, 5, h, e, l, l, o, // value 1 1594 0xff, 0xff, 0xff, 0xff, // value 2 1595 0xff, 0xff, 0xff, 0xfe, // value 3 1596 }, 1597 &Query{ 1598 Query: "SELECT", 1599 Options: &QueryOptions{ 1600 PositionalValues: []*primitive.Value{ 1601 { 1602 Type: primitive.ValueTypeRegular, 1603 Contents: []byte{h, e, l, l, o}, 1604 }, 1605 { 1606 Type: primitive.ValueTypeNull, 1607 }, 1608 { 1609 Type: primitive.ValueTypeUnset, 1610 }, 1611 }, 1612 }, 1613 }, 1614 nil, 1615 }, 1616 { 1617 "query with named values", 1618 []byte{ 1619 0, 0, 0, 6, S, E, L, E, C, T, 1620 0, 0, // consistency level 1621 0b0100_0001, // flags 1622 0, 1, // values length 1623 0, 4, c, o, l, _1, // name 1 1624 0, 0, 0, 5, h, e, l, l, o, // value 1 1625 }, 1626 &Query{ 1627 Query: "SELECT", 1628 Options: &QueryOptions{ 1629 NamedValues: map[string]*primitive.Value{ 1630 "col1": { 1631 Type: primitive.ValueTypeRegular, 1632 Contents: []byte{h, e, l, l, o}, 1633 }, 1634 }, 1635 }, 1636 }, 1637 nil, 1638 }, 1639 { 1640 "query with empty query string", 1641 []byte{ 1642 0, 0, 0, 0, // empty query 1643 0, 0, // consistency level 1644 0, // flags 1645 }, 1646 &Query{ 1647 Query: "", 1648 Options: &QueryOptions{}, 1649 }, 1650 nil, 1651 }, 1652 } 1653 for _, tt := range tests { 1654 t.Run(tt.name, func(t *testing.T) { 1655 source := bytes.NewBuffer(tt.input) 1656 actual, err := codec.Decode(source, primitive.ProtocolVersion4) 1657 assert.Equal(t, tt.expected, actual) 1658 assert.Equal(t, tt.err, err) 1659 }) 1660 } 1661 }) 1662 // tests for version = 5 1663 t.Run(primitive.ProtocolVersion5.String(), func(t *testing.T) { 1664 tests := []decodeTestCase{ 1665 { 1666 "query with keyspace and now-in-seconds", 1667 []byte{ 1668 0, 0, 0, 6, S, E, L, E, C, T, 1669 0, 0, // consistency level 1670 0b0000_0000, // flags 1671 0b0000_0000, // flags 1672 0b0000_0001, // flags (keyspace) 1673 0b1000_0000, // flags (now in seconds) 1674 0, 3, k, s, _1, // keyspace 1675 0, 0, 0, 123, // now in seconds 1676 }, 1677 &Query{ 1678 Query: "SELECT", 1679 Options: &QueryOptions{ 1680 Keyspace: "ks1", 1681 NowInSeconds: int32Ptr(123), 1682 }, 1683 }, 1684 nil, 1685 }, 1686 { 1687 "query with positional values, keyspace and now-in-seconds", 1688 []byte{ 1689 0, 0, 0, 6, S, E, L, E, C, T, 1690 0, 0, // consistency level 1691 0b0000_0000, // flags 1692 0b0000_0000, // flags 1693 0b0000_0001, // flags 1694 0b1000_0001, // flags 1695 0, 3, // values length 1696 0, 0, 0, 5, h, e, l, l, o, // value 1 1697 0xff, 0xff, 0xff, 0xff, // value 2 1698 0xff, 0xff, 0xff, 0xfe, // value 3 1699 0, 3, k, s, _1, // keyspace 1700 0, 0, 0, 123, // now in seconds 1701 }, 1702 &Query{ 1703 Query: "SELECT", 1704 Options: &QueryOptions{ 1705 Keyspace: "ks1", 1706 NowInSeconds: int32Ptr(123), 1707 PositionalValues: []*primitive.Value{ 1708 { 1709 Type: primitive.ValueTypeRegular, 1710 Contents: []byte{h, e, l, l, o}, 1711 }, 1712 { 1713 Type: primitive.ValueTypeNull, 1714 }, 1715 { 1716 Type: primitive.ValueTypeUnset, 1717 }, 1718 }, 1719 }, 1720 }, 1721 nil, 1722 }, 1723 } 1724 for _, tt := range tests { 1725 t.Run(tt.name, func(t *testing.T) { 1726 source := bytes.NewBuffer(tt.input) 1727 actual, err := codec.Decode(source, primitive.ProtocolVersion5) 1728 assert.Equal(t, tt.expected, actual) 1729 assert.Equal(t, tt.err, err) 1730 }) 1731 } 1732 }) 1733 // tests for version = DSE v1 1734 t.Run(primitive.ProtocolVersionDse1.String(), func(t *testing.T) { 1735 tests := []struct { 1736 name string 1737 input []byte 1738 expected Message 1739 err error 1740 }{ 1741 { 1742 "query with default options", 1743 []byte{ 1744 0, 0, 0, 6, S, E, L, E, C, T, 1745 0, 0, // consistency level 1746 0, 0, 0, 0, // flags 1747 }, 1748 &Query{ 1749 Query: "SELECT", 1750 Options: &QueryOptions{}, 1751 }, 1752 nil, 1753 }, 1754 { 1755 "query with custom options and no values", 1756 []byte{ 1757 0, 0, 0, 6, S, E, L, E, C, T, 1758 0, 6, // consistency level 1759 0b1100_0000, 0, 0, 0b0011_1110, // flags (cont. paging and page size bytes) 1760 0, 0, 0, 100, // page size 1761 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 1762 0, 9, // serial consistency level 1763 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 1764 0, 0, 0, 50, // max pages 1765 0, 0, 0, 10, // pages per sec 1766 }, 1767 &Query{ 1768 Query: "SELECT", 1769 Options: &QueryOptions{ 1770 Consistency: primitive.ConsistencyLevelLocalQuorum, 1771 SkipMetadata: true, 1772 PageSize: 100, 1773 PageSizeInBytes: true, 1774 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 1775 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1776 DefaultTimestamp: int64Ptr(123), 1777 ContinuousPagingOptions: &ContinuousPagingOptions{MaxPages: 50, PagesPerSecond: 10}, 1778 }, 1779 }, 1780 nil, 1781 }, 1782 { 1783 "query with positional values", 1784 []byte{ 1785 0, 0, 0, 6, S, E, L, E, C, T, 1786 0, 0, // consistency level 1787 0, 0, 0, 0b0000_0001, // flags 1788 0, 3, // values length 1789 0, 0, 0, 5, h, e, l, l, o, // value 1 1790 0xff, 0xff, 0xff, 0xff, // value 2 1791 0xff, 0xff, 0xff, 0xfe, // value 3 1792 }, 1793 &Query{ 1794 Query: "SELECT", 1795 Options: &QueryOptions{ 1796 PositionalValues: []*primitive.Value{ 1797 { 1798 Type: primitive.ValueTypeRegular, 1799 Contents: []byte{h, e, l, l, o}, 1800 }, 1801 { 1802 Type: primitive.ValueTypeNull, 1803 }, 1804 { 1805 Type: primitive.ValueTypeUnset, 1806 }, 1807 }, 1808 }, 1809 }, 1810 nil, 1811 }, 1812 { 1813 "query with named values", 1814 []byte{ 1815 0, 0, 0, 6, S, E, L, E, C, T, 1816 0, 0, // consistency level 1817 0, 0, 0, 0b0100_0001, // flags 1818 0, 1, // values length 1819 0, 4, c, o, l, _1, // name 1 1820 0, 0, 0, 5, h, e, l, l, o, // value 1 1821 }, 1822 &Query{ 1823 Query: "SELECT", 1824 Options: &QueryOptions{ 1825 NamedValues: map[string]*primitive.Value{ 1826 "col1": { 1827 Type: primitive.ValueTypeRegular, 1828 Contents: []byte{h, e, l, l, o}, 1829 }, 1830 }, 1831 }, 1832 }, 1833 nil, 1834 }, 1835 { 1836 "query with empty query string", 1837 []byte{ 1838 0, 0, 0, 0, // empty query 1839 0, 0, // consistency level 1840 0, 0, 0, 0, // flags 1841 }, 1842 &Query{ 1843 Query: "", 1844 Options: &QueryOptions{}, 1845 }, 1846 nil, 1847 }, 1848 } 1849 for _, tt := range tests { 1850 t.Run(tt.name, func(t *testing.T) { 1851 source := bytes.NewBuffer(tt.input) 1852 actual, err := codec.Decode(source, primitive.ProtocolVersionDse1) 1853 assert.Equal(t, tt.expected, actual) 1854 assert.Equal(t, tt.err, err) 1855 }) 1856 } 1857 }) 1858 // tests for version = DSE v2 1859 t.Run(primitive.ProtocolVersionDse2.String(), func(t *testing.T) { 1860 tests := []decodeTestCase{ 1861 { 1862 "query with keyspace and continuous paging", 1863 []byte{ 1864 0, 0, 0, 6, S, E, L, E, C, T, 1865 0, 0, // consistency level 1866 0b1000_0000, // flags (cont. paging) 1867 0b0000_0000, // flags 1868 0b0000_0000, // flags 1869 0b1000_0000, // flags (keyspace) 1870 0, 3, k, s, _1, // keyspace 1871 0, 0, 0, 50, // max pages 1872 0, 0, 0, 10, // pages per sec 1873 0, 0, 0, 20, // next pages 1874 }, 1875 &Query{ 1876 Query: "SELECT", 1877 Options: &QueryOptions{ 1878 Keyspace: "ks1", 1879 ContinuousPagingOptions: &ContinuousPagingOptions{MaxPages: 50, PagesPerSecond: 10, NextPages: 20}, 1880 }, 1881 }, 1882 nil, 1883 }, 1884 { 1885 "query with custom options and no values", 1886 []byte{ 1887 0, 0, 0, 6, S, E, L, E, C, T, 1888 0, 6, // consistency level 1889 0b1100_0000, 0, 0, 0b0011_1110, // flags 1890 0, 0, 0, 100, // page size 1891 0, 0, 0, 4, 0xca, 0xfe, 0xba, 0xbe, // paging state 1892 0, 9, // serial consistency level 1893 0, 0, 0, 0, 0, 0, 0, 123, // default timestamp 1894 0, 0, 0, 50, // max pages 1895 0, 0, 0, 10, // pages per sec 1896 0, 0, 0, 20, // next pages 1897 }, 1898 &Query{ 1899 Query: "SELECT", 1900 Options: &QueryOptions{ 1901 Consistency: primitive.ConsistencyLevelLocalQuorum, 1902 SkipMetadata: true, 1903 PageSize: 100, 1904 PageSizeInBytes: true, 1905 PagingState: []byte{0xca, 0xfe, 0xba, 0xbe}, 1906 SerialConsistency: consistencyLevelPtr(primitive.ConsistencyLevelLocalSerial), 1907 DefaultTimestamp: int64Ptr(123), 1908 ContinuousPagingOptions: &ContinuousPagingOptions{MaxPages: 50, PagesPerSecond: 10, NextPages: 20}, 1909 }, 1910 }, 1911 nil, 1912 }, 1913 { 1914 "query with positional values and keyspace", 1915 []byte{ 1916 0, 0, 0, 6, S, E, L, E, C, T, 1917 0, 0, // consistency level 1918 0b0000_0000, // flags 1919 0b0000_0000, // flags 1920 0b0000_0000, // flags 1921 0b1000_0001, // flags (keyspace | values) 1922 0, 3, // values length 1923 0, 0, 0, 5, h, e, l, l, o, // value 1 1924 0xff, 0xff, 0xff, 0xff, // value 2 1925 0xff, 0xff, 0xff, 0xfe, // value 3 1926 0, 3, k, s, _1, // keyspace 1927 }, 1928 &Query{ 1929 Query: "SELECT", 1930 Options: &QueryOptions{ 1931 Keyspace: "ks1", 1932 PositionalValues: []*primitive.Value{ 1933 { 1934 Type: primitive.ValueTypeRegular, 1935 Contents: []byte{h, e, l, l, o}, 1936 }, 1937 { 1938 Type: primitive.ValueTypeNull, 1939 }, 1940 { 1941 Type: primitive.ValueTypeUnset, 1942 }, 1943 }, 1944 }, 1945 }, 1946 nil, 1947 }, 1948 } 1949 for _, tt := range tests { 1950 t.Run(tt.name, func(t *testing.T) { 1951 source := bytes.NewBuffer(tt.input) 1952 actual, err := codec.Decode(source, primitive.ProtocolVersionDse2) 1953 assert.Equal(t, tt.expected, actual) 1954 assert.Equal(t, tt.err, err) 1955 }) 1956 } 1957 }) 1958 }