vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/sequence/seq_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sequence
    18  
    19  import (
    20  	"context"
    21  	"flag"
    22  	"fmt"
    23  	"os"
    24  	"strings"
    25  	"testing"
    26  
    27  	"vitess.io/vitess/go/test/endtoend/utils"
    28  
    29  	"github.com/stretchr/testify/assert"
    30  
    31  	"github.com/stretchr/testify/require"
    32  
    33  	"vitess.io/vitess/go/mysql"
    34  	"vitess.io/vitess/go/test/endtoend/cluster"
    35  )
    36  
    37  var (
    38  	clusterInstance    *cluster.LocalProcessCluster
    39  	cell               = "zone1"
    40  	hostname           = "localhost"
    41  	unshardedKs        = "uks"
    42  	unshardedSQLSchema = `
    43  	create table sequence_test(
    44  		id bigint,
    45  		val varchar(16),
    46  		primary key(id)
    47  	)Engine=InnoDB;
    48  
    49  	create table sequence_test_seq (
    50  		id int default 0,
    51  		next_id bigint default null,
    52  		cache bigint default null,
    53  		primary key(id)
    54  	) comment 'vitess_sequence' Engine=InnoDB;
    55  
    56  CREATE TABLE id_seq ( id INT, next_id BIGINT, cache BIGINT, PRIMARY KEY(id)) comment 'vitess_sequence';
    57  
    58  INSERT INTO id_seq (id, next_id, cache) values (0, 1, 1000);
    59  
    60  	`
    61  
    62  	unshardedVSchema = `
    63  		{
    64  			"sharded":false,
    65  			"vindexes": {
    66  				"hash_index": {
    67  					"type": "hash"
    68  				}
    69  			},
    70  			"tables": {
    71  				"sequence_test":{
    72  					"auto_increment":{
    73  						"column" : "id",
    74  						"sequence" : "sequence_test_seq"
    75  					},
    76  					"column_vindexes": [
    77  						{
    78  							"column": "id",
    79  							"name": "hash_index"
    80  						}
    81  					]
    82  				},
    83  				"sequence_test_seq": {
    84  					"type":   "sequence"
    85  				},
    86                  "id_seq": {
    87                      "type": "sequence"
    88                   }
    89  			}
    90  		}
    91  `
    92  
    93  	shardedKeyspaceName = `sks`
    94  
    95  	shardedSQLSchema = `
    96  CREATE TABLE ` + "`dotted.tablename`" + ` (
    97      id BIGINT NOT NULL,
    98      c1 DOUBLE NOT NULL,
    99      c2 BIGINT,
   100      PRIMARY KEY (id),
   101      UNIQUE KEY (c1, c2)
   102  );
   103  
   104  CREATE TABLE lookup_vindex (
   105      c1 DOUBLE NOT NULL,
   106      c2 BIGINT,
   107      keyspace_id BLOB,
   108      UNIQUE KEY (c1, c2)
   109  );
   110  
   111  CREATE TABLE allDefaults (
   112      id bigint NOT NULL,
   113      foo varchar(255),
   114      primary key (id)
   115  );`
   116  
   117  	shardedVSchema = `
   118  		{
   119  		  "sharded": true,
   120  		  "vindexes": {
   121  			"lookup_vindex": {
   122  			  "type": "consistent_lookup",
   123  			  "params": {
   124  				"from": "c1,c2",
   125  				"table": "lookup_vindex",
   126  				"to": "keyspace_id"
   127  			  },
   128  			  "owner": "dotted.tablename"
   129  			},
   130  			"hash": {
   131  			  "type": "hash"
   132  			}
   133  		  },
   134  		  "tables": {
   135  			"dotted.tablename": {
   136  			  "columnVindexes": [
   137  				{
   138  				  "column": "id",
   139  				  "name": "hash"
   140  				},
   141  				{
   142  				  "name": "lookup_vindex",
   143  				  "columns": [ "c1", "c2" ]
   144  				}
   145  			  ],
   146  			  "autoIncrement": {
   147  				"column": "id",
   148  				"sequence": "id_seq"
   149  			  }
   150  			},
   151  			"allDefaults": {
   152  			  "columnVindexes": [
   153  				{
   154  				  "column": "id",
   155  				  "name": "hash"
   156  				}
   157                ],
   158  			  "autoIncrement": {
   159  				"column": "id",
   160  				"sequence": "id_seq"
   161  			  }
   162  			},
   163  			"lookup_vindex": {
   164  			  "columnVindexes": [
   165  				{
   166  				  "column": "c1",
   167  				  "name": "hash"
   168  				}
   169  			  ]
   170  			}
   171  		  }
   172  		}`
   173  )
   174  
   175  func TestMain(m *testing.M) {
   176  	defer cluster.PanicHandler(nil)
   177  	flag.Parse()
   178  
   179  	exitCode := func() int {
   180  		clusterInstance = cluster.NewCluster(cell, hostname)
   181  		defer clusterInstance.Teardown()
   182  
   183  		// Start topo server
   184  		if err := clusterInstance.StartTopo(); err != nil {
   185  			return 1
   186  		}
   187  
   188  		// Start keyspace
   189  		uKeyspace := &cluster.Keyspace{
   190  			Name:      unshardedKs,
   191  			SchemaSQL: unshardedSQLSchema,
   192  			VSchema:   unshardedVSchema,
   193  		}
   194  		if err := clusterInstance.StartUnshardedKeyspace(*uKeyspace, 1, false); err != nil {
   195  			return 1
   196  		}
   197  
   198  		sKeyspace := &cluster.Keyspace{
   199  			Name:      shardedKeyspaceName,
   200  			SchemaSQL: shardedSQLSchema,
   201  			VSchema:   shardedVSchema,
   202  		}
   203  		if err := clusterInstance.StartKeyspace(*sKeyspace, []string{"-80", "80-"}, 1, false); err != nil {
   204  			return 1
   205  		}
   206  
   207  		// Start vtgate
   208  		if err := clusterInstance.StartVtgate(); err != nil {
   209  			return 1
   210  		}
   211  
   212  		return m.Run()
   213  	}()
   214  	os.Exit(exitCode)
   215  }
   216  
   217  func TestSeq(t *testing.T) {
   218  	defer cluster.PanicHandler(t)
   219  	ctx := context.Background()
   220  	vtParams := mysql.ConnParams{
   221  		Host: "localhost",
   222  		Port: clusterInstance.VtgateMySQLPort,
   223  	}
   224  	conn, err := mysql.Connect(ctx, &vtParams)
   225  	require.Nil(t, err)
   226  	defer conn.Close()
   227  
   228  	//Initialize seq table
   229  	utils.Exec(t, conn, "insert into sequence_test_seq(id, next_id, cache) values(0,1,10)")
   230  
   231  	//Insert 4 values in the main table
   232  	utils.Exec(t, conn, "insert into sequence_test(val) values('a'), ('b') ,('c'), ('d')")
   233  
   234  	// Test select calls to main table and verify expected id.
   235  	qr := utils.Exec(t, conn, "select id, val  from sequence_test where id=4")
   236  	if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(4) VARCHAR("d")]]`; got != want {
   237  		t.Errorf("select:\n%v want\n%v", got, want)
   238  	}
   239  
   240  	// Test next available seq id from cache
   241  	qr = utils.Exec(t, conn, "select next 1 values from sequence_test_seq")
   242  	if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(5)]]`; got != want {
   243  		t.Errorf("select:\n%v want\n%v", got, want)
   244  	}
   245  
   246  	// Test next_id from seq table which should be the increased by cache value(id+cache)
   247  	qr = utils.Exec(t, conn, "select next_id from sequence_test_seq")
   248  	if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(11)]]`; got != want {
   249  		t.Errorf("select:\n%v want\n%v", got, want)
   250  	}
   251  
   252  	// Test insert with no auto-inc
   253  	utils.Exec(t, conn, "insert into sequence_test(id, val) values(6, 'f')")
   254  	qr = utils.Exec(t, conn, "select * from sequence_test")
   255  	if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(1) VARCHAR("a")] [INT64(2) VARCHAR("b")] [INT64(3) VARCHAR("c")] [INT64(4) VARCHAR("d")] [INT64(6) VARCHAR("f")]]`; got != want {
   256  		t.Errorf("select:\n%v want\n%v", got, want)
   257  	}
   258  
   259  	// Next insert will fail as we have corrupted the sequence
   260  	utils.Exec(t, conn, "begin")
   261  	_, err = conn.ExecuteFetch("insert into sequence_test(val) values('g')", 1000, false)
   262  	utils.Exec(t, conn, "rollback")
   263  	want := "Duplicate entry"
   264  	if err == nil || !strings.Contains(err.Error(), want) {
   265  		t.Errorf("wrong insert: %v, must contain %s", err, want)
   266  	}
   267  
   268  	utils.Exec(t, conn, "DELETE FROM sequence_test_seq")
   269  	qr = utils.Exec(t, conn, "select * from sequence_test_seq")
   270  	if got, want := fmt.Sprintf("%v", qr.Rows), `[]`; got != want {
   271  		t.Errorf("select:\n%v want\n%v", got, want)
   272  	}
   273  }
   274  
   275  func TestDotTableSeq(t *testing.T) {
   276  	defer cluster.PanicHandler(t)
   277  	ctx := context.Background()
   278  	vtParams := mysql.ConnParams{
   279  		Host:   "localhost",
   280  		Port:   clusterInstance.VtgateMySQLPort,
   281  		DbName: shardedKeyspaceName,
   282  	}
   283  	conn, err := mysql.Connect(ctx, &vtParams)
   284  	require.NoError(t, err)
   285  	defer conn.Close()
   286  
   287  	_, err = conn.ExecuteFetch("insert into `dotted.tablename` (c1,c2) values (10,10)", 1000, true)
   288  	require.NoError(t, err)
   289  
   290  	_, err = conn.ExecuteFetch("insert into `dotted.tablename` (c1,c2) values (10,10)", 1000, true)
   291  	require.Error(t, err)
   292  	mysqlErr := err.(*mysql.SQLError)
   293  	assert.Equal(t, 1062, mysqlErr.Num)
   294  	assert.Equal(t, "23000", mysqlErr.State)
   295  	assert.Contains(t, mysqlErr.Message, "Duplicate entry")
   296  }
   297  
   298  func TestInsertAllDefaults(t *testing.T) {
   299  	defer cluster.PanicHandler(t)
   300  	ctx := context.Background()
   301  	vtParams := mysql.ConnParams{
   302  		Host:   "localhost",
   303  		Port:   clusterInstance.VtgateMySQLPort,
   304  		DbName: shardedKeyspaceName,
   305  	}
   306  	conn, err := mysql.Connect(ctx, &vtParams)
   307  	require.NoError(t, err)
   308  	defer conn.Close()
   309  
   310  	// inserting into a table that has default values for all columns works well
   311  	utils.Exec(t, conn, `insert into allDefaults () values ()`)
   312  	result := utils.Exec(t, conn, `select * from uks.id_seq`)
   313  	assert.Equal(t, 1, len(result.Rows))
   314  
   315  	// inserting into a table that does not have default values for all columns fails
   316  	_, err = conn.ExecuteFetch("insert into lookup_vindex () values ()", 0, false)
   317  	require.Error(t, err)
   318  }