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 }