vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/errors_as_warnings/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 vtgate 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/require" 30 31 "vitess.io/vitess/go/mysql" 32 "vitess.io/vitess/go/test/endtoend/cluster" 33 ) 34 35 var ( 36 clusterInstance *cluster.LocalProcessCluster 37 vtParams mysql.ConnParams 38 KeyspaceName = "ks" 39 Cell = "test" 40 SchemaSQL = `create table t1( 41 id1 bigint, 42 id2 bigint, 43 primary key(id1) 44 ) Engine=InnoDB;` 45 46 VSchema = ` 47 { 48 "sharded": true, 49 "vindexes": { 50 "hash": { 51 "type": "hash" 52 } 53 }, 54 "tables": { 55 "t1": { 56 "column_vindexes": [ 57 { 58 "column": "id1", 59 "name": "hash" 60 } 61 ] 62 } 63 } 64 }` 65 ) 66 67 func TestMain(m *testing.M) { 68 defer cluster.PanicHandler(nil) 69 flag.Parse() 70 71 exitCode := func() int { 72 clusterInstance = cluster.NewCluster(Cell, "localhost") 73 defer clusterInstance.Teardown() 74 75 // Start topo server 76 err := clusterInstance.StartTopo() 77 if err != nil { 78 return 1 79 } 80 81 // Start keyspace 82 keyspace := &cluster.Keyspace{ 83 Name: KeyspaceName, 84 SchemaSQL: SchemaSQL, 85 VSchema: VSchema, 86 } 87 if err := clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 1, false); err != nil { 88 return 1 89 } 90 91 // Start vtgate 92 if err := clusterInstance.StartVtgate(); err != nil { 93 return 1 94 } 95 96 vtParams = clusterInstance.GetVTParams(KeyspaceName) 97 return m.Run() 98 }() 99 os.Exit(exitCode) 100 } 101 102 func TestScatterErrsAsWarns(t *testing.T) { 103 if clusterInstance.HasPartialKeyspaces { 104 t.Skip("test kills primary on source shard, but query will be on target shard so it will be skipped") 105 } 106 oltp, err := mysql.Connect(context.Background(), &vtParams) 107 require.NoError(t, err) 108 defer oltp.Close() 109 110 olap, err := mysql.Connect(context.Background(), &vtParams) 111 require.NoError(t, err) 112 defer olap.Close() 113 114 utils.Exec(t, oltp, `insert into t1(id1, id2) values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)`) 115 defer func() { 116 utils.Exec(t, oltp, "use @primary") 117 utils.Exec(t, oltp, `delete from t1`) 118 }() 119 120 query1 := `select /*vt+ SCATTER_ERRORS_AS_WARNINGS */ id1 from t1` 121 query2 := `select /*vt+ SCATTER_ERRORS_AS_WARNINGS */ id1 from t1 order by id1` 122 showQ := "show warnings" 123 124 // stop the mysql on one tablet, query will fail at vttablet level 125 require.NoError(t, 126 clusterInstance.Keyspaces[0].Shards[0].Replica().MysqlctlProcess.Stop()) 127 128 modes := []struct { 129 conn *mysql.Conn 130 m string 131 }{ 132 {m: "oltp", conn: oltp}, 133 {m: "olap", conn: olap}, 134 } 135 136 for _, mode := range modes { 137 t.Run(mode.m, func(t *testing.T) { 138 // connection setup 139 utils.Exec(t, mode.conn, "use @replica") 140 utils.Exec(t, mode.conn, fmt.Sprintf("set workload = %s", mode.m)) 141 142 utils.AssertMatches(t, mode.conn, query1, `[[INT64(4)]]`) 143 assertContainsOneOf(t, mode.conn, showQ, "no valid tablet", "no healthy tablet", "mysql.sock: connect: no such file or directory") 144 utils.AssertMatches(t, mode.conn, query2, `[[INT64(4)]]`) 145 assertContainsOneOf(t, mode.conn, showQ, "no valid tablet", "no healthy tablet", "mysql.sock: connect: no such file or directory") 146 147 // invalid_field should throw error and not warning 148 _, err = mode.conn.ExecuteFetch("SELECT /*vt+ PLANNER=Gen4 SCATTER_ERRORS_AS_WARNINGS */ invalid_field from t1;", 1, false) 149 require.Error(t, err) 150 serr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) 151 require.Equal(t, 1054, serr.Number(), serr.Error()) 152 }) 153 } 154 } 155 156 func assertContainsOneOf(t *testing.T, conn *mysql.Conn, query string, expected ...string) { 157 t.Helper() 158 qr := utils.Exec(t, conn, query) 159 got := fmt.Sprintf("%v", qr.Rows) 160 for _, s := range expected { 161 if strings.Contains(got, s) { 162 return 163 } 164 } 165 166 t.Errorf("%s\n did not match any of %v", got, expected) 167 }