vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/partialfailure/main_test.go (about)

     1  /*
     2  Copyright 2021 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 reservedconn
    18  
    19  import (
    20  	"context"
    21  	"flag"
    22  	"os"
    23  	"testing"
    24  
    25  	"vitess.io/vitess/go/test/endtoend/utils"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"vitess.io/vitess/go/mysql"
    30  	"vitess.io/vitess/go/test/endtoend/cluster"
    31  )
    32  
    33  var (
    34  	clusterInstance *cluster.LocalProcessCluster
    35  	vtParams        mysql.ConnParams
    36  	keyspaceName    = "ks"
    37  	cell            = "zone1"
    38  	hostname        = "localhost"
    39  	sqlSchema       = `
    40  	create table test(
    41  		id bigint,
    42  		val1 varchar(16),
    43  		val2 int,
    44  		val3 float,
    45  		primary key(id)
    46  	)Engine=InnoDB;
    47  
    48  CREATE TABLE test_vdx (
    49      val1 varchar(16) NOT NULL,
    50      keyspace_id binary(8),
    51      UNIQUE KEY (val1)
    52  ) ENGINE=Innodb;
    53  `
    54  
    55  	vSchema = `
    56  		{	
    57  			"sharded":true,
    58  			"vindexes": {
    59  				"hash_index": {
    60  					"type": "hash"
    61  				},
    62  				"lookup1": {
    63  					"type": "consistent_lookup",
    64  					"params": {
    65  						"table": "test_vdx",
    66  						"from": "val1",
    67  						"to": "keyspace_id",
    68  						"ignore_nulls": "true"
    69  					},
    70  					"owner": "test"
    71  				},
    72  				"unicode_vdx":{
    73  					"type": "unicode_loose_md5"
    74                  }
    75  			},	
    76  			"tables": {
    77  				"test":{
    78  					"column_vindexes": [
    79  						{
    80  							"column": "id",
    81  							"name": "hash_index"
    82  						},
    83  						{
    84  							"column": "val1",
    85  							"name": "lookup1"
    86  						}
    87  					]
    88  				},
    89  				"test_vdx":{
    90  					"column_vindexes": [
    91  						{
    92  							"column": "val1",
    93  							"name": "unicode_vdx"
    94  						}
    95  					]
    96  				}
    97  			}
    98  		}
    99  	`
   100  )
   101  
   102  func TestMain(m *testing.M) {
   103  	defer cluster.PanicHandler(nil)
   104  	flag.Parse()
   105  
   106  	exitCode := func() int {
   107  		clusterInstance = cluster.NewCluster(cell, hostname)
   108  		defer clusterInstance.Teardown()
   109  
   110  		// Start topo server
   111  		if err := clusterInstance.StartTopo(); err != nil {
   112  			return 1
   113  		}
   114  
   115  		// Start keyspace
   116  		keyspace := &cluster.Keyspace{
   117  			Name:      keyspaceName,
   118  			SchemaSQL: sqlSchema,
   119  			VSchema:   vSchema,
   120  		}
   121  		if err := clusterInstance.StartKeyspace(*keyspace, []string{"-40", "40-80", "80-c0", "c0-"}, 0, false); err != nil {
   122  
   123  			return 1
   124  		}
   125  
   126  		// Start vtgate
   127  		clusterInstance.VtGateExtraArgs = append(clusterInstance.VtGateExtraArgs, "--planner-version", "Gen4Fallback")
   128  		if err := clusterInstance.StartVtgate(); err != nil {
   129  			return 1
   130  		}
   131  		vtParams = clusterInstance.GetVTParams(keyspaceName)
   132  		return m.Run()
   133  	}()
   134  	os.Exit(exitCode)
   135  }
   136  
   137  func testAllModes(t *testing.T, stmts func(conn *mysql.Conn)) {
   138  	t.Helper()
   139  
   140  	tcases := []struct {
   141  		mode string
   142  		qs   []string
   143  	}{
   144  		{"oltp", []string{"set workload = oltp"}},
   145  		{"oltp-reserved", []string{"set workload = oltp", "set sql_mode = ''"}},
   146  		{"olap", []string{"set workload = olap"}},
   147  		{"olap-reserved", []string{"set workload = olap", "set sql_mode = ''"}},
   148  	}
   149  
   150  	for _, tc := range tcases {
   151  		t.Run(tc.mode, func(t *testing.T) {
   152  			conn, err := mysql.Connect(context.Background(), &vtParams)
   153  			require.NoError(t, err)
   154  			defer conn.Close()
   155  
   156  			// setup the mode
   157  			for _, q := range tc.qs {
   158  				utils.Exec(t, conn, q)
   159  			}
   160  
   161  			// cleanup previous run data from table.
   162  			utils.Exec(t, conn, `delete from test`)
   163  
   164  			// execute all the test stmts.
   165  			stmts(conn)
   166  		})
   167  	}
   168  }
   169  func TestPartialQueryFailureExplicitTx(t *testing.T) {
   170  	testAllModes(t, func(conn *mysql.Conn) {
   171  		utils.Exec(t, conn, `begin`)
   172  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   173  		// primary vindex is duplicate
   174  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (1,'D'),(4,'E')`, `reverted partial DML execution failure`)
   175  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   176  		utils.Exec(t, conn, `commit`)
   177  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   178  	})
   179  }
   180  
   181  func TestPartialVindexQueryFailureExplicitTx(t *testing.T) {
   182  	testAllModes(t, func(conn *mysql.Conn) {
   183  		utils.Exec(t, conn, `begin`)
   184  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   185  		// lookup vindex is duplicate
   186  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (4,'D'),(5,'C')`, `reverted partial DML execution failure`)
   187  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   188  		utils.Exec(t, conn, `insert into test(id, val1) values (4,'D'),(5,'E')`)
   189  		utils.Exec(t, conn, `commit`)
   190  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")] [INT64(4) VARCHAR("D")] [INT64(5) VARCHAR("E")]]`)
   191  	})
   192  }
   193  
   194  func TestPartialQueryFailureNoAutoCommit(t *testing.T) {
   195  	testAllModes(t, func(conn *mysql.Conn) {
   196  		// autocommit is false.
   197  		utils.Exec(t, conn, `set autocommit = off`)
   198  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   199  		// primary vindex is duplicate
   200  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (1,'D'),(4,'E')`, `reverted partial DML execution failure`)
   201  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   202  		utils.Exec(t, conn, `commit`)
   203  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   204  	})
   205  }
   206  
   207  func TestPartialVindexQueryFailureNoAutoCommit(t *testing.T) {
   208  	testAllModes(t, func(conn *mysql.Conn) {
   209  		// autocommit is false.
   210  		utils.Exec(t, conn, `set autocommit = off`)
   211  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   212  		// lookup vindex is duplicate
   213  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (4,'D'),(5,'C')`, `reverted partial DML execution failure`)
   214  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   215  		utils.Exec(t, conn, `insert into test(id, val1) values (4,'D'),(5,'E')`)
   216  		utils.Exec(t, conn, `commit`)
   217  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")] [INT64(4) VARCHAR("D")] [INT64(5) VARCHAR("E")]]`)
   218  	})
   219  }
   220  
   221  func TestPartialQueryFailureAutoCommit(t *testing.T) {
   222  	testAllModes(t, func(conn *mysql.Conn) {
   223  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   224  		// primary vindex is duplicate, transaction is rolled back as it was an implicit transaction started by vtgate.
   225  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (1,'D'),(4,'E')`, `transaction rolled back to reverse changes of partial DML execution`)
   226  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   227  		// commit will not have any effect on the state in autocommit mode.
   228  		utils.Exec(t, conn, `commit`)
   229  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   230  	})
   231  }
   232  
   233  func TestPartialVindexQueryFailureAutoCommit(t *testing.T) {
   234  	testAllModes(t, func(conn *mysql.Conn) {
   235  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   236  		// lookup vindex is duplicate, transaction is rolled back as it was an implicit transaction started by vtgate.
   237  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (4,'D'),(5,'C')`, `transaction rolled back to reverse changes of partial DML execution`)
   238  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   239  		utils.Exec(t, conn, `insert into test(id, val1) values (4,'D'),(5,'E')`)
   240  		// commit will not have any effect on the state in autocommit mode.
   241  		utils.Exec(t, conn, `commit`)
   242  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")] [INT64(4) VARCHAR("D")] [INT64(5) VARCHAR("E")]]`)
   243  	})
   244  }
   245  
   246  func TestPartialQueryFailureRollback(t *testing.T) {
   247  	testAllModes(t, func(conn *mysql.Conn) {
   248  		utils.Exec(t, conn, `begin`)
   249  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   250  		// primary vindex is duplicate
   251  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (1,'D'),(4,'E')`, `reverted partial DML execution failure`)
   252  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   253  		utils.Exec(t, conn, `rollback`)
   254  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[]`)
   255  	})
   256  }
   257  
   258  func TestPartialVindexQueryFailureRollback(t *testing.T) {
   259  	testAllModes(t, func(conn *mysql.Conn) {
   260  		utils.Exec(t, conn, `begin`)
   261  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   262  		// lookup vindex is duplicate
   263  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (4,'D'),(5,'C')`, `reverted partial DML execution failure`)
   264  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   265  		utils.Exec(t, conn, `insert into test(id, val1) values (4,'D'),(5,'E')`)
   266  		utils.Exec(t, conn, `rollback`)
   267  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[]`)
   268  	})
   269  }
   270  
   271  func TestPartialQueryFailureNoAutoCommitRollback(t *testing.T) {
   272  	testAllModes(t, func(conn *mysql.Conn) {
   273  		// autocommit is false.
   274  		utils.Exec(t, conn, `set autocommit = off`)
   275  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   276  		// primary vindex is duplicate
   277  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (1,'D'),(4,'E')`, `reverted partial DML execution failure`)
   278  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   279  		utils.Exec(t, conn, `rollback`)
   280  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[]`)
   281  	})
   282  }
   283  
   284  func TestPartialVindexQueryFailureNoAutoCommitRollback(t *testing.T) {
   285  	testAllModes(t, func(conn *mysql.Conn) {
   286  		// autocommit is false.  y 6
   287  		utils.Exec(t, conn, `set autocommit = off`)
   288  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   289  		// lookup vindex is duplicate
   290  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (4,'D'),(5,'C')`, `reverted partial DML execution failure`)
   291  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   292  		utils.Exec(t, conn, `insert into test(id, val1) values (4,'D'),(5,'E')`)
   293  		utils.Exec(t, conn, `rollback`)
   294  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[]`)
   295  	})
   296  }
   297  
   298  func TestPartialQueryFailureAutoCommitRollback(t *testing.T) {
   299  	testAllModes(t, func(conn *mysql.Conn) {
   300  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   301  		// primary vindex is duplicate, transaction is rolled back as it was an implicit transaction started by vtgate.
   302  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (1,'D'),(4,'E')`, `transaction rolled back to reverse changes of partial DML execution`)
   303  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   304  		// rollback will not have any effect on the state in autocommit mode.
   305  		utils.Exec(t, conn, `rollback`)
   306  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   307  	})
   308  }
   309  
   310  func TestPartialVindexQueryFailureAutoCommitRollback(t *testing.T) {
   311  	testAllModes(t, func(conn *mysql.Conn) {
   312  		utils.Exec(t, conn, `insert into test(id, val1) values (1,'A'),(2,'B'),(3,'C')`)
   313  		// lookup vindex is duplicate, transaction is rolled back as it was an implicit transaction started by vtgate.
   314  		utils.AssertContainsError(t, conn, `insert into test(id, val1) values (4,'D'),(5,'C')`, `transaction rolled back to reverse changes of partial DML execution`)
   315  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")]]`)
   316  		utils.Exec(t, conn, `insert into test(id, val1) values (4,'D'),(5,'E')`)
   317  		// rollback will not have any effect on the state in autocommit mode.
   318  		utils.Exec(t, conn, `rollback`)
   319  		utils.AssertMatches(t, conn, `select id, val1 from test order by id`, `[[INT64(1) VARCHAR("A")] [INT64(2) VARCHAR("B")] [INT64(3) VARCHAR("C")] [INT64(4) VARCHAR("D")] [INT64(5) VARCHAR("E")]]`)
   320  	})
   321  }