github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/client/client_remote_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 client_test
    16  
    17  import (
    18  	"context"
    19  	"encoding/binary"
    20  	"fmt"
    21  	"github.com/datastax/go-cassandra-native-protocol/client"
    22  	"github.com/datastax/go-cassandra-native-protocol/datatype"
    23  	"github.com/datastax/go-cassandra-native-protocol/frame"
    24  	"github.com/datastax/go-cassandra-native-protocol/message"
    25  	"github.com/datastax/go-cassandra-native-protocol/primitive"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  	"math"
    29  	"sync"
    30  	"testing"
    31  	"time"
    32  )
    33  
    34  // This test requires a remote server listening on localhost:9042 without authentication.
    35  func TestRemoteServerNoAuth(t *testing.T) {
    36  	if !remoteAvailable {
    37  		t.Skip("No remote cluster available")
    38  	}
    39  	for _, version := range primitive.SupportedProtocolVersions() {
    40  		t.Run(version.String(), func(t *testing.T) {
    41  
    42  			for genName, generator := range streamIdGenerators {
    43  				t.Run(fmt.Sprintf("generator %v", genName), func(t *testing.T) {
    44  
    45  					for _, compression := range compressions {
    46  						if version.SupportsCompression(compression) {
    47  							t.Run(fmt.Sprintf("%v", compression), func(t *testing.T) {
    48  
    49  								clt := client.NewCqlClient("127.0.0.1:9042", nil)
    50  								clt.Compression = compression
    51  								if version <= primitive.ProtocolVersion2 {
    52  									clt.MaxInFlight = math.MaxInt8
    53  								}
    54  								clientTest(t, clt, version, generator, compression != primitive.CompressionNone, version.IsDse())
    55  
    56  							})
    57  						}
    58  					}
    59  				})
    60  			}
    61  		})
    62  	}
    63  }
    64  
    65  // This test requires a remote server listening on localhost:9042 with authentication.
    66  func TestRemoteServerAuth(t *testing.T) {
    67  	if !remoteAvailable {
    68  		t.Skip("No remote cluster available")
    69  	}
    70  	for _, version := range primitive.SupportedProtocolVersions() {
    71  		t.Run(version.String(), func(t *testing.T) {
    72  
    73  			for genName, generator := range streamIdGenerators {
    74  				t.Run(fmt.Sprintf("generator %v", genName), func(t *testing.T) {
    75  
    76  					for _, compression := range compressions {
    77  						if version.SupportsCompression(compression) {
    78  							t.Run(fmt.Sprintf("%v", compression), func(t *testing.T) {
    79  
    80  								clt := client.NewCqlClient(
    81  									"127.0.0.1:9042",
    82  									&client.AuthCredentials{Username: "cassandra", Password: "cassandra"},
    83  								)
    84  								clt.Compression = compression
    85  
    86  								clientTest(t, clt, version, generator, compression != primitive.CompressionNone, version.IsDse())
    87  							})
    88  						}
    89  					}
    90  				})
    91  			}
    92  		})
    93  	}
    94  }
    95  
    96  func clientTest(
    97  	t *testing.T,
    98  	clt *client.CqlClient,
    99  	version primitive.ProtocolVersion,
   100  	generator func(int, primitive.ProtocolVersion) int16,
   101  	compress bool,
   102  	continuousPaging bool,
   103  ) {
   104  	ks := fmt.Sprintf("ks_%d", time.Now().UnixNano())
   105  	table := fmt.Sprintf("t_%d", time.Now().UnixNano())
   106  
   107  	eventsCount := 0
   108  	clt.EventHandlers = []client.EventHandler{checkEventsReceived(t, &eventsCount, ks, table)}
   109  
   110  	ctx, cancel := context.WithCancel(context.Background())
   111  	defer cancel()
   112  
   113  	clientConn, err := clt.ConnectAndInit(ctx, version, generator(1, version))
   114  	require.NoError(t, err)
   115  	require.False(t, clientConn.IsClosed())
   116  
   117  	registerForSchemaChanges(t, clientConn, version, generator, compress)
   118  	createSchema(t, clientConn, ks, table, version, generator, compress)
   119  
   120  	require.GreaterOrEqual(t, eventsCount, 2)
   121  
   122  	insertData(t, clientConn, ks, table, version, generator, compress)
   123  	insertDataBatch(t, clientConn, ks, table, version, generator, compress)
   124  	insertDataPrepared(t, clientConn, ks, table, version, generator, compress)
   125  	insertDataBatchPrepared(t, clientConn, ks, table, version, generator, compress)
   126  
   127  	retrieveData(t, clientConn, ks, table, version, generator, compress)
   128  	retrieveDataPrepared(t, clientConn, ks, table, version, generator, compress)
   129  	if continuousPaging {
   130  		retrieveDataContinuousPaging(t, clientConn, ks, table, version, generator, compress)
   131  	}
   132  
   133  	truncate(t, clientConn, ks, table, version, generator, compress)
   134  	insertAndRetrieveLargeData(t, clientConn, ks, table, version, generator, compress)
   135  
   136  	dropSchema(t, clientConn, ks, version, generator, compress)
   137  	checkEventsByChannel(t, clientConn)
   138  	require.GreaterOrEqual(t, eventsCount, 4)
   139  
   140  	cancel()
   141  	assert.Eventually(t, clientConn.IsClosed, time.Second*10, time.Millisecond*10)
   142  
   143  }
   144  
   145  func checkEventsReceived(t *testing.T, eventsCount *int, ks string, table string) client.EventHandler {
   146  	return func(event *frame.Frame, conn *client.CqlClientConnection) {
   147  		assert.Equal(t, primitive.OpCodeEvent, event.Header.OpCode)
   148  		assert.EqualValues(t, -1, event.Header.StreamId)
   149  		assert.IsType(t, &message.SchemaChangeEvent{}, event.Body.Message)
   150  		sce := event.Body.Message.(*message.SchemaChangeEvent)
   151  		if *eventsCount == 0 {
   152  			assert.Equal(t, primitive.SchemaChangeTargetKeyspace, sce.Target)
   153  			assert.Equal(t, primitive.SchemaChangeTypeCreated, sce.ChangeType)
   154  			assert.Equal(t, ks, sce.Keyspace)
   155  			assert.Equal(t, "", sce.Object)
   156  		} else if *eventsCount == 1 {
   157  			assert.Equal(t, primitive.SchemaChangeTargetTable, sce.Target)
   158  			assert.Equal(t, primitive.SchemaChangeTypeCreated, sce.ChangeType)
   159  			assert.Equal(t, ks, sce.Keyspace)
   160  			assert.Equal(t, table, sce.Object)
   161  		} else {
   162  			assert.Equal(t, primitive.SchemaChangeTypeDropped, sce.ChangeType)
   163  		}
   164  		*eventsCount++
   165  	}
   166  }
   167  
   168  func checkEventsByChannel(t *testing.T, clientConn *client.CqlClientConnection) {
   169  	// expect 4 events, 2 CREATED, 2 DROPPED // 2 KEYSPACE, 2 TABLE
   170  	created := 0
   171  	dropped := 0
   172  	ks := 0
   173  	table := 0
   174  	for i := 0; i < 4; i++ {
   175  		event, err := clientConn.ReceiveEvent()
   176  		require.NoError(t, err)
   177  		assert.EqualValues(t, -1, event.Header.StreamId)
   178  		assert.IsType(t, &message.SchemaChangeEvent{}, event.Body.Message)
   179  		sce := event.Body.Message.(*message.SchemaChangeEvent)
   180  		switch sce.ChangeType {
   181  		case primitive.SchemaChangeTypeCreated:
   182  			created++
   183  		case primitive.SchemaChangeTypeDropped:
   184  			dropped++
   185  		}
   186  		switch sce.Target {
   187  		case primitive.SchemaChangeTargetKeyspace:
   188  			ks++
   189  		case primitive.SchemaChangeTargetTable:
   190  			table++
   191  		}
   192  	}
   193  	assert.Equal(t, 2, created)
   194  	assert.Equal(t, 2, dropped)
   195  	assert.Equal(t, 2, ks)
   196  	assert.Equal(t, 2, table)
   197  }
   198  
   199  func registerForSchemaChanges(
   200  	t *testing.T,
   201  	clientConn *client.CqlClientConnection,
   202  	version primitive.ProtocolVersion,
   203  	generator func(int, primitive.ProtocolVersion) int16,
   204  	compress bool,
   205  ) {
   206  	request := frame.NewFrame(
   207  		version,
   208  		generator(1, version),
   209  		&message.Register{EventTypes: []primitive.EventType{primitive.EventTypeSchemaChange}},
   210  	)
   211  	request.SetCompress(compress)
   212  	response, err := clientConn.SendAndReceive(request)
   213  	require.NoError(t, err)
   214  	require.IsType(t, &message.Ready{}, response.Body.Message)
   215  }
   216  
   217  func createSchema(
   218  	t *testing.T,
   219  	clientConn *client.CqlClientConnection,
   220  	ks string,
   221  	table string,
   222  	version primitive.ProtocolVersion,
   223  	generator func(int, primitive.ProtocolVersion) int16,
   224  	compress bool,
   225  ) {
   226  	request := frame.NewFrame(
   227  		version,
   228  		generator(1, version),
   229  		&message.Query{
   230  			Query: fmt.Sprintf("CREATE KEYSPACE %s "+
   231  				"WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} "+
   232  				"AND durable_writes = true", ks),
   233  		},
   234  	)
   235  	request.SetCompress(compress)
   236  	response, err := clientConn.SendAndReceive(request)
   237  	require.NoError(t, err)
   238  	require.IsType(t, &message.SchemaChangeResult{}, response.Body.Message)
   239  	result := response.Body.Message.(*message.SchemaChangeResult)
   240  	require.Equal(t, result.ChangeType, primitive.SchemaChangeTypeCreated)
   241  	require.Equal(t, result.Target, primitive.SchemaChangeTargetKeyspace)
   242  	require.Equal(t, result.Keyspace, ks)
   243  	require.Equal(t, result.Object, "")
   244  	request = frame.NewFrame(
   245  		version,
   246  		generator(1, version),
   247  		&message.Query{
   248  			Query: fmt.Sprintf("CREATE TABLE %s.%s "+
   249  				"(pk int, cc int, v int, PRIMARY KEY (pk, cc))", ks, table),
   250  		},
   251  	)
   252  	request.SetCompress(compress)
   253  	response, err = clientConn.SendAndReceive(request)
   254  	require.NoError(t, err)
   255  	require.IsType(t, &message.SchemaChangeResult{}, response.Body.Message)
   256  	result = response.Body.Message.(*message.SchemaChangeResult)
   257  	require.Equal(t, result.ChangeType, primitive.SchemaChangeTypeCreated)
   258  	require.Equal(t, result.Target, primitive.SchemaChangeTargetTable)
   259  	require.Equal(t, result.Keyspace, ks)
   260  	require.Equal(t, result.Object, table)
   261  }
   262  
   263  func truncate(
   264  	t *testing.T,
   265  	clientConn *client.CqlClientConnection,
   266  	ks string,
   267  	table string,
   268  	version primitive.ProtocolVersion,
   269  	generator func(int, primitive.ProtocolVersion) int16,
   270  	compress bool,
   271  ) {
   272  	request := frame.NewFrame(
   273  		version,
   274  		generator(1, version),
   275  		&message.Query{
   276  			Query: fmt.Sprintf("TRUNCATE %s.%s", ks, table),
   277  		},
   278  	)
   279  	request.SetCompress(compress)
   280  	response, err := clientConn.SendAndReceive(request)
   281  	require.NoError(t, err)
   282  	require.IsType(t, &message.VoidResult{}, response.Body.Message)
   283  }
   284  
   285  func dropSchema(
   286  	t *testing.T,
   287  	clientConn *client.CqlClientConnection,
   288  	ks string,
   289  	version primitive.ProtocolVersion,
   290  	generator func(int, primitive.ProtocolVersion) int16,
   291  	compress bool,
   292  ) {
   293  	request := frame.NewFrame(
   294  		version,
   295  		generator(1, version),
   296  		&message.Query{
   297  			Query: fmt.Sprintf("DROP KEYSPACE %s", ks),
   298  		},
   299  	)
   300  	request.SetCompress(compress)
   301  	response, err := clientConn.SendAndReceive(request)
   302  	require.NoError(t, err)
   303  	require.IsType(t, &message.SchemaChangeResult{}, response.Body.Message)
   304  	result := response.Body.Message.(*message.SchemaChangeResult)
   305  	require.Equal(t, result.ChangeType, primitive.SchemaChangeTypeDropped)
   306  	require.Equal(t, result.Target, primitive.SchemaChangeTargetKeyspace)
   307  	require.Equal(t, result.Keyspace, ks)
   308  	require.Equal(t, result.Object, "")
   309  }
   310  
   311  func insertData(
   312  	t *testing.T,
   313  	clientConn *client.CqlClientConnection,
   314  	ks string,
   315  	table string,
   316  	version primitive.ProtocolVersion,
   317  	generator func(int, primitive.ProtocolVersion) int16,
   318  	compress bool,
   319  ) {
   320  	wg := &sync.WaitGroup{}
   321  	for i := 1; i <= 10; i++ {
   322  		wg.Add(1)
   323  		go func(i int) {
   324  			defer wg.Done()
   325  			for j := 1; j <= 10; j++ {
   326  				pk := make([]byte, 4)
   327  				cc := make([]byte, 4)
   328  				v := make([]byte, 4)
   329  				binary.BigEndian.PutUint32(pk, uint32(i))
   330  				binary.BigEndian.PutUint32(cc, uint32(j))
   331  				binary.BigEndian.PutUint32(v, uint32(i)*uint32(j))
   332  				request := frame.NewFrame(
   333  					version,
   334  					generator(i, version),
   335  					&message.Query{
   336  						Query: fmt.Sprintf("INSERT INTO %s.%s (pk, cc, v) VALUES (?,?,?)", ks, table),
   337  						Options: &message.QueryOptions{
   338  							Consistency: primitive.ConsistencyLevelOne,
   339  							PositionalValues: []*primitive.Value{
   340  								primitive.NewValue(pk),
   341  								primitive.NewValue(cc),
   342  								primitive.NewValue(v),
   343  							},
   344  						},
   345  					},
   346  				)
   347  				request.SetCompress(compress)
   348  				response, err := clientConn.SendAndReceive(request)
   349  				require.NoError(t, err)
   350  				require.IsType(t, &message.VoidResult{}, response.Body.Message)
   351  			}
   352  		}(i)
   353  	}
   354  	wg.Wait()
   355  }
   356  
   357  func insertDataPrepared(
   358  	t *testing.T,
   359  	clientConn *client.CqlClientConnection,
   360  	ks string,
   361  	table string,
   362  	version primitive.ProtocolVersion,
   363  	generator func(int, primitive.ProtocolVersion) int16,
   364  	compress bool,
   365  ) {
   366  	prepared := prepareInsert(t, clientConn, ks, table, version, generator, compress)
   367  	wg := &sync.WaitGroup{}
   368  	for i := 1; i <= 10; i++ {
   369  		wg.Add(1)
   370  		go func(i int) {
   371  			defer wg.Done()
   372  			for j := 1; j <= 10; j++ {
   373  				pk := make([]byte, 4)
   374  				cc := make([]byte, 4)
   375  				v := make([]byte, 4)
   376  				binary.BigEndian.PutUint32(pk, uint32(i))
   377  				binary.BigEndian.PutUint32(cc, uint32(j))
   378  				binary.BigEndian.PutUint32(v, uint32(i)*uint32(j))
   379  				request := frame.NewFrame(
   380  					version,
   381  					generator(i, version),
   382  					&message.Execute{
   383  						QueryId:          prepared.PreparedQueryId,
   384  						ResultMetadataId: prepared.ResultMetadataId,
   385  						Options: &message.QueryOptions{
   386  							Consistency: primitive.ConsistencyLevelOne,
   387  							PositionalValues: []*primitive.Value{
   388  								primitive.NewValue(pk),
   389  								primitive.NewValue(cc),
   390  								primitive.NewValue(v),
   391  							},
   392  						},
   393  					},
   394  				)
   395  				request.SetCompress(compress)
   396  				response, err := clientConn.SendAndReceive(request)
   397  				require.NoError(t, err)
   398  				require.IsType(t, &message.VoidResult{}, response.Body.Message)
   399  			}
   400  		}(i)
   401  	}
   402  	wg.Wait()
   403  }
   404  
   405  func insertDataBatch(
   406  	t *testing.T,
   407  	clientConn *client.CqlClientConnection,
   408  	ks string,
   409  	table string,
   410  	version primitive.ProtocolVersion,
   411  	generator func(int, primitive.ProtocolVersion) int16,
   412  	compress bool,
   413  ) {
   414  	wg := &sync.WaitGroup{}
   415  	for i := 1; i <= 10; i++ {
   416  		wg.Add(1)
   417  		go func(i int) {
   418  			defer wg.Done()
   419  			children := make([]*message.BatchChild, 10)
   420  			for j := 1; j <= 10; j++ {
   421  				pk := make([]byte, 4)
   422  				cc := make([]byte, 4)
   423  				v := make([]byte, 4)
   424  				binary.BigEndian.PutUint32(pk, uint32(i))
   425  				binary.BigEndian.PutUint32(cc, uint32(j))
   426  				binary.BigEndian.PutUint32(v, uint32(i)*uint32(j))
   427  				children[j-1] = &message.BatchChild{
   428  					Query: fmt.Sprintf("INSERT INTO %s.%s (pk, cc, v) VALUES (?,?,?)", ks, table),
   429  					Values: []*primitive.Value{
   430  						primitive.NewValue(pk),
   431  						primitive.NewValue(cc),
   432  						primitive.NewValue(v),
   433  					},
   434  				}
   435  			}
   436  			request := frame.NewFrame(
   437  				version,
   438  				generator(i, version),
   439  				&message.Batch{
   440  					Consistency: primitive.ConsistencyLevelLocalOne,
   441  					Children:    children,
   442  				},
   443  			)
   444  			request.SetCompress(compress)
   445  			response, err := clientConn.SendAndReceive(request)
   446  			require.NoError(t, err)
   447  			require.IsType(t, &message.VoidResult{}, response.Body.Message)
   448  		}(i)
   449  	}
   450  	wg.Wait()
   451  }
   452  
   453  func insertDataBatchPrepared(
   454  	t *testing.T,
   455  	clientConn *client.CqlClientConnection,
   456  	ks string,
   457  	table string,
   458  	version primitive.ProtocolVersion,
   459  	generator func(int, primitive.ProtocolVersion) int16,
   460  	compress bool,
   461  ) {
   462  	prepared := prepareInsert(t, clientConn, ks, table, version, generator, compress)
   463  	wg := &sync.WaitGroup{}
   464  	for i := 1; i <= 10; i++ {
   465  		wg.Add(1)
   466  		go func(i int) {
   467  			defer wg.Done()
   468  			children := make([]*message.BatchChild, 10)
   469  			for j := 1; j <= 10; j++ {
   470  				pk := make([]byte, 4)
   471  				cc := make([]byte, 4)
   472  				v := make([]byte, 4)
   473  				binary.BigEndian.PutUint32(pk, uint32(i))
   474  				binary.BigEndian.PutUint32(cc, uint32(j))
   475  				binary.BigEndian.PutUint32(v, uint32(i)*uint32(j))
   476  				children[j-1] = &message.BatchChild{
   477  					Id: prepared.PreparedQueryId,
   478  					Values: []*primitive.Value{
   479  						primitive.NewValue(pk),
   480  						primitive.NewValue(cc),
   481  						primitive.NewValue(v),
   482  					},
   483  				}
   484  			}
   485  			request := frame.NewFrame(
   486  				version,
   487  				generator(i, version),
   488  				&message.Batch{
   489  					Consistency: primitive.ConsistencyLevelLocalOne,
   490  					Children:    children,
   491  				},
   492  			)
   493  			request.SetCompress(compress)
   494  			response, err := clientConn.SendAndReceive(request)
   495  			require.NoError(t, err)
   496  			require.IsType(t, &message.VoidResult{}, response.Body.Message)
   497  
   498  		}(i)
   499  	}
   500  	wg.Wait()
   501  }
   502  
   503  func retrieveData(
   504  	t *testing.T,
   505  	clientConn *client.CqlClientConnection,
   506  	ks string,
   507  	table string,
   508  	version primitive.ProtocolVersion,
   509  	generator func(int, primitive.ProtocolVersion) int16,
   510  	compress bool,
   511  ) {
   512  	wg := &sync.WaitGroup{}
   513  	for i := 1; i <= 10; i++ {
   514  		wg.Add(1)
   515  		go func(i int) {
   516  			defer wg.Done()
   517  			for j := 1; j <= 10; j++ {
   518  				pk := make([]byte, 4)
   519  				cc := make([]byte, 4)
   520  				binary.BigEndian.PutUint32(pk, uint32(i))
   521  				binary.BigEndian.PutUint32(cc, uint32(j))
   522  				request := frame.NewFrame(
   523  					version,
   524  					generator(i, version),
   525  					&message.Query{
   526  						Query: fmt.Sprintf("SELECT v FROM %s.%s WHERE pk = ? AND cc = ?", ks, table),
   527  						Options: &message.QueryOptions{
   528  							Consistency: primitive.ConsistencyLevelOne,
   529  							PositionalValues: []*primitive.Value{
   530  								primitive.NewValue(pk),
   531  								primitive.NewValue(cc),
   532  							},
   533  						},
   534  					},
   535  				)
   536  				request.SetCompress(compress)
   537  				response, err := clientConn.SendAndReceive(request)
   538  				require.NoError(t, err)
   539  				require.IsType(t, &message.RowsResult{}, response.Body.Message)
   540  				result := response.Body.Message.(*message.RowsResult)
   541  				require.Len(t, result.Data, 1)
   542  				row := result.Data[0]
   543  				require.Len(t, row, 1)
   544  				column := row[0]
   545  				require.Len(t, column, 4)
   546  				v := binary.BigEndian.Uint32(column)
   547  				require.Equal(t, uint32(i*j), v)
   548  			}
   549  		}(i)
   550  	}
   551  	wg.Wait()
   552  }
   553  
   554  func retrieveDataPrepared(
   555  	t *testing.T,
   556  	clientConn *client.CqlClientConnection,
   557  	ks string,
   558  	table string,
   559  	version primitive.ProtocolVersion,
   560  	generator func(int, primitive.ProtocolVersion) int16,
   561  	compress bool,
   562  ) {
   563  	prepared := prepareSelect(t, clientConn, ks, table, version, generator, compress)
   564  	wg := &sync.WaitGroup{}
   565  	for i := 1; i <= 10; i++ {
   566  		wg.Add(1)
   567  		go func(i int) {
   568  			defer wg.Done()
   569  			for j := 1; j <= 10; j++ {
   570  				pk := make([]byte, 4)
   571  				cc := make([]byte, 4)
   572  				binary.BigEndian.PutUint32(pk, uint32(i))
   573  				binary.BigEndian.PutUint32(cc, uint32(j))
   574  				request := frame.NewFrame(
   575  					version,
   576  					generator(i, version),
   577  					&message.Execute{
   578  						QueryId:          prepared.PreparedQueryId,
   579  						ResultMetadataId: prepared.ResultMetadataId,
   580  						Options: &message.QueryOptions{
   581  							Consistency: primitive.ConsistencyLevelOne,
   582  							PositionalValues: []*primitive.Value{
   583  								primitive.NewValue(pk),
   584  								primitive.NewValue(cc),
   585  							},
   586  						},
   587  					},
   588  				)
   589  				request.SetCompress(compress)
   590  				response, err := clientConn.SendAndReceive(request)
   591  				require.NoError(t, err)
   592  				require.IsType(t, &message.RowsResult{}, response.Body.Message)
   593  				result := response.Body.Message.(*message.RowsResult)
   594  				require.Len(t, result.Data, 1)
   595  				row := result.Data[0]
   596  				require.Len(t, row, 1)
   597  				column := row[0]
   598  				require.Len(t, column, 4)
   599  				v := binary.BigEndian.Uint32(column)
   600  				require.Equal(t, uint32(i*j), v)
   601  			}
   602  		}(i)
   603  	}
   604  	wg.Wait()
   605  }
   606  
   607  func retrieveDataContinuousPaging(
   608  	t *testing.T,
   609  	clientConn *client.CqlClientConnection,
   610  	ks string,
   611  	table string,
   612  	version primitive.ProtocolVersion,
   613  	generator func(int, primitive.ProtocolVersion) int16,
   614  	compress bool,
   615  ) {
   616  	request := frame.NewFrame(
   617  		version,
   618  		generator(1, version),
   619  		&message.Query{
   620  			Query: fmt.Sprintf("SELECT v FROM %s.%s", ks, table),
   621  			Options: &message.QueryOptions{
   622  				Consistency:             primitive.ConsistencyLevelLocalOne,
   623  				PageSize:                10,
   624  				ContinuousPagingOptions: &message.ContinuousPagingOptions{MaxPages: 5},
   625  			},
   626  		},
   627  	)
   628  	request.SetCompress(compress)
   629  
   630  	ch, err := clientConn.Send(request)
   631  	require.NoError(t, err)
   632  
   633  	for i := 1; i <= 5; i++ {
   634  		f, err := clientConn.Receive(ch)
   635  		require.NoError(t, err)
   636  		require.NotNil(t, f)
   637  		require.IsType(t, &message.RowsResult{}, f.Body.Message)
   638  		result := f.Body.Message.(*message.RowsResult)
   639  		assert.Equal(t, result.Metadata.ContinuousPageNumber, int32(i))
   640  		assert.Equal(t, result.Metadata.LastContinuousPage, i == 5)
   641  		assert.Len(t, result.Data, 10)
   642  	}
   643  
   644  	request = frame.NewFrame(
   645  		version,
   646  		generator(1, version),
   647  		&message.Revise{
   648  			RevisionType:   primitive.DseRevisionTypeCancelContinuousPaging,
   649  			TargetStreamId: int32(request.Header.StreamId),
   650  		},
   651  	)
   652  	request.SetCompress(compress)
   653  
   654  	response, err := clientConn.SendAndReceive(request)
   655  	require.NoError(t, err)
   656  	require.IsType(t, &message.RowsResult{}, response.Body.Message)
   657  	result := response.Body.Message.(*message.RowsResult)
   658  	require.Len(t, result.Data, 1)
   659  	row := result.Data[0]
   660  	require.Len(t, row, 1)
   661  	column := row[0]
   662  	require.Len(t, column, 1) // boolean
   663  }
   664  
   665  func prepareInsert(
   666  	t *testing.T,
   667  	clientConn *client.CqlClientConnection,
   668  	ks string,
   669  	table string,
   670  	version primitive.ProtocolVersion,
   671  	generator func(int, primitive.ProtocolVersion) int16,
   672  	compress bool,
   673  ) *message.PreparedResult {
   674  	request := frame.NewFrame(
   675  		version,
   676  		generator(1, version),
   677  		&message.Prepare{
   678  			Query: fmt.Sprintf("INSERT INTO %s.%s (pk, cc, v) VALUES (?,?,?)", ks, table),
   679  		},
   680  	)
   681  	request.SetCompress(compress)
   682  	response, err := clientConn.SendAndReceive(request)
   683  	require.NoError(t, err)
   684  	require.IsType(t, &message.PreparedResult{}, response.Body.Message)
   685  	prepared := response.Body.Message.(*message.PreparedResult)
   686  	assert.Len(t, prepared.VariablesMetadata.Columns, 3)
   687  	assert.Equal(t, ks, prepared.VariablesMetadata.Columns[0].Keyspace)
   688  	assert.Equal(t, table, prepared.VariablesMetadata.Columns[0].Table)
   689  	assert.Equal(t, "pk", prepared.VariablesMetadata.Columns[0].Name)
   690  	assert.Equal(t, datatype.Int, prepared.VariablesMetadata.Columns[0].Type)
   691  	assert.Equal(t, ks, prepared.VariablesMetadata.Columns[1].Keyspace)
   692  	assert.Equal(t, table, prepared.VariablesMetadata.Columns[1].Table)
   693  	assert.Equal(t, "cc", prepared.VariablesMetadata.Columns[1].Name)
   694  	assert.Equal(t, datatype.Int, prepared.VariablesMetadata.Columns[1].Type)
   695  	assert.Equal(t, ks, prepared.VariablesMetadata.Columns[2].Keyspace)
   696  	assert.Equal(t, table, prepared.VariablesMetadata.Columns[2].Table)
   697  	assert.Equal(t, "v", prepared.VariablesMetadata.Columns[2].Name)
   698  	assert.Equal(t, datatype.Int, prepared.VariablesMetadata.Columns[2].Type)
   699  	if version >= primitive.ProtocolVersion4 {
   700  		assert.Equal(t, prepared.VariablesMetadata.PkIndices, []uint16{0})
   701  	}
   702  	assert.Zero(t, prepared.ResultMetadata.ColumnCount)
   703  	assert.Nil(t, prepared.ResultMetadata.Columns)
   704  	return prepared
   705  }
   706  
   707  func prepareSelect(
   708  	t *testing.T,
   709  	clientConn *client.CqlClientConnection,
   710  	ks string,
   711  	table string,
   712  	version primitive.ProtocolVersion,
   713  	generator func(int, primitive.ProtocolVersion) int16,
   714  	compress bool,
   715  ) *message.PreparedResult {
   716  	request := frame.NewFrame(
   717  		version,
   718  		generator(1, version),
   719  		&message.Prepare{
   720  			Query: fmt.Sprintf("SELECT v FROM %s.%s WHERE pk = ? AND cc = ?", ks, table),
   721  		},
   722  	)
   723  	request.SetCompress(compress)
   724  	response, err := clientConn.SendAndReceive(request)
   725  	require.NoError(t, err)
   726  	require.IsType(t, &message.PreparedResult{}, response.Body.Message)
   727  	prepared := response.Body.Message.(*message.PreparedResult)
   728  	assert.Len(t, prepared.VariablesMetadata.Columns, 2)
   729  	assert.Equal(t, ks, prepared.VariablesMetadata.Columns[0].Keyspace)
   730  	assert.Equal(t, table, prepared.VariablesMetadata.Columns[0].Table)
   731  	assert.Equal(t, "pk", prepared.VariablesMetadata.Columns[0].Name)
   732  	assert.Equal(t, datatype.Int, prepared.VariablesMetadata.Columns[0].Type)
   733  	assert.Equal(t, ks, prepared.VariablesMetadata.Columns[1].Keyspace)
   734  	assert.Equal(t, table, prepared.VariablesMetadata.Columns[1].Table)
   735  	assert.Equal(t, "cc", prepared.VariablesMetadata.Columns[1].Name)
   736  	assert.Equal(t, datatype.Int, prepared.VariablesMetadata.Columns[1].Type)
   737  	if version >= primitive.ProtocolVersion4 {
   738  		assert.Equal(t, prepared.VariablesMetadata.PkIndices, []uint16{0})
   739  	}
   740  	assert.EqualValues(t, 1, prepared.ResultMetadata.ColumnCount)
   741  	assert.Len(t, prepared.ResultMetadata.Columns, 1)
   742  	assert.Equal(t, ks, prepared.ResultMetadata.Columns[0].Keyspace)
   743  	assert.Equal(t, table, prepared.ResultMetadata.Columns[0].Table)
   744  	assert.Equal(t, "v", prepared.ResultMetadata.Columns[0].Name)
   745  	assert.Equal(t, datatype.Int, prepared.ResultMetadata.Columns[0].Type)
   746  	return prepared
   747  }
   748  
   749  func insertAndRetrieveLargeData(
   750  	t *testing.T,
   751  	clientConn *client.CqlClientConnection,
   752  	ks string,
   753  	table string,
   754  	version primitive.ProtocolVersion,
   755  	generator func(int, primitive.ProtocolVersion) int16,
   756  	compress bool,
   757  ) {
   758  	// generate enough data to trigger a multi-segment response in protocol v5
   759  	for i := 1; i <= 10000; i++ {
   760  		pk := make([]byte, 4)
   761  		cc := make([]byte, 4)
   762  		v := make([]byte, 4)
   763  		binary.BigEndian.PutUint32(pk, uint32(i))
   764  		binary.BigEndian.PutUint32(cc, uint32(i))
   765  		binary.BigEndian.PutUint32(v, uint32(i))
   766  		request := frame.NewFrame(
   767  			version,
   768  			generator(i, version),
   769  			&message.Query{
   770  				Query: fmt.Sprintf("INSERT INTO %s.%s (pk, cc, v) VALUES (?,?,?)", ks, table),
   771  				Options: &message.QueryOptions{
   772  					Consistency: primitive.ConsistencyLevelOne,
   773  					PositionalValues: []*primitive.Value{
   774  						primitive.NewValue(pk),
   775  						primitive.NewValue(cc),
   776  						primitive.NewValue(v),
   777  					},
   778  				},
   779  			},
   780  		)
   781  		request.SetCompress(compress)
   782  		response, err := clientConn.SendAndReceive(request)
   783  		require.NoError(t, err)
   784  		require.IsType(t, &message.VoidResult{}, response.Body.Message)
   785  	}
   786  	request := frame.NewFrame(
   787  		version,
   788  		generator(1, version),
   789  		&message.Query{
   790  			Query: fmt.Sprintf("SELECT * FROM %s.%s", ks, table),
   791  			Options: &message.QueryOptions{
   792  				Consistency: primitive.ConsistencyLevelOne,
   793  			},
   794  		},
   795  	)
   796  	request.SetCompress(compress)
   797  	response, err := clientConn.SendAndReceive(request)
   798  	require.NoError(t, err)
   799  	require.IsType(t, &message.RowsResult{}, response.Body.Message)
   800  	result := response.Body.Message.(*message.RowsResult)
   801  	require.Len(t, result.Data, 10000)
   802  }