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