vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/schematracker/sharded/st_sharded_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 sharded 18 19 import ( 20 "context" 21 _ "embed" 22 "flag" 23 "fmt" 24 "os" 25 "testing" 26 "time" 27 28 "github.com/stretchr/testify/assert" 29 30 "vitess.io/vitess/go/test/endtoend/utils" 31 "vitess.io/vitess/go/vt/vtgate/planbuilder" 32 33 "github.com/stretchr/testify/require" 34 35 "vitess.io/vitess/go/mysql" 36 "vitess.io/vitess/go/test/endtoend/cluster" 37 ) 38 39 var ( 40 clusterInstance *cluster.LocalProcessCluster 41 vtParams mysql.ConnParams 42 KeyspaceName = "ks" 43 Cell = "test" 44 //go:embed schema.sql 45 SchemaSQL string 46 47 //go:embed vschema.json 48 VSchema string 49 ) 50 51 func TestMain(m *testing.M) { 52 defer cluster.PanicHandler(nil) 53 flag.Parse() 54 55 exitCode := func() int { 56 clusterInstance = cluster.NewCluster(Cell, "localhost") 57 defer clusterInstance.Teardown() 58 59 // Start topo server 60 err := clusterInstance.StartTopo() 61 if err != nil { 62 return 1 63 } 64 65 // Start keyspace 66 keyspace := &cluster.Keyspace{ 67 Name: KeyspaceName, 68 SchemaSQL: SchemaSQL, 69 VSchema: VSchema, 70 } 71 clusterInstance.VtGateExtraArgs = []string{"--schema_change_signal", 72 "--vschema_ddl_authorized_users", "%", 73 "--schema_change_signal_user", "userData1"} 74 clusterInstance.VtGatePlannerVersion = planbuilder.Gen4 75 clusterInstance.VtTabletExtraArgs = []string{"--queryserver-config-schema-change-signal", 76 "--queryserver-config-schema-change-signal-interval", "0.1", 77 "--queryserver-config-strict-table-acl", 78 "--queryserver-config-acl-exempt-acl", "userData1", 79 "--table-acl-config", "dummy.json"} 80 81 vtgateVer, err := cluster.GetMajorVersion("vtgate") 82 if err != nil { 83 return 1 84 } 85 vttabletVer, err := cluster.GetMajorVersion("vttablet") 86 if err != nil { 87 return 1 88 } 89 if vtgateVer >= 16 && vttabletVer >= 16 { 90 clusterInstance.VtGateExtraArgs = append(clusterInstance.VtGateExtraArgs, "--enable-views") 91 clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, "--queryserver-enable-views") 92 } 93 94 err = clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 0, false) 95 if err != nil { 96 return 1 97 } 98 99 // Start vtgate 100 err = clusterInstance.StartVtgate() 101 if err != nil { 102 return 1 103 } 104 105 vtParams = mysql.ConnParams{ 106 Host: clusterInstance.Hostname, 107 Port: clusterInstance.VtgateMySQLPort, 108 } 109 return m.Run() 110 }() 111 os.Exit(exitCode) 112 } 113 114 func TestNewTable(t *testing.T) { 115 ctx := context.Background() 116 conn, err := mysql.Connect(ctx, &vtParams) 117 require.NoError(t, err) 118 defer conn.Close() 119 120 shard1Params := vtParams 121 shard1Params.DbName += ":-80@primary" 122 connShard1, err := mysql.Connect(ctx, &shard1Params) 123 require.NoError(t, err) 124 defer connShard1.Close() 125 126 shard2Params := vtParams 127 shard2Params.DbName += ":80-@primary" 128 connShard2, err := mysql.Connect(ctx, &shard2Params) 129 require.NoError(t, err) 130 defer connShard2.Close() 131 132 _ = utils.Exec(t, conn, "create table test_table (id bigint, name varchar(100))") 133 134 time.Sleep(2 * time.Second) 135 136 utils.AssertMatches(t, conn, "select * from test_table", `[]`) 137 utils.AssertMatches(t, connShard1, "select * from test_table", `[]`) 138 utils.AssertMatches(t, connShard2, "select * from test_table", `[]`) 139 140 utils.Exec(t, conn, "drop table test_table") 141 142 time.Sleep(2 * time.Second) 143 } 144 145 func TestAmbiguousColumnJoin(t *testing.T) { 146 defer cluster.PanicHandler(t) 147 ctx := context.Background() 148 conn, err := mysql.Connect(ctx, &vtParams) 149 require.NoError(t, err) 150 defer conn.Close() 151 // this query only works if we know which table the testId belongs to. The vschema does not contain 152 // this info, so we are testing that the schema tracker has added column info to the vschema 153 _, err = conn.ExecuteFetch(`select testId from t8 join t2`, 1000, true) 154 require.NoError(t, err) 155 } 156 157 func TestInitAndUpdate(t *testing.T) { 158 ctx := context.Background() 159 conn, err := mysql.Connect(ctx, &vtParams) 160 require.NoError(t, err) 161 defer conn.Close() 162 163 vtgateVersion, err := cluster.GetMajorVersion("vtgate") 164 require.NoError(t, err) 165 166 expected := `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]` 167 if vtgateVersion >= 17 { 168 expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]` 169 } 170 utils.AssertMatchesWithTimeout(t, conn, 171 "SHOW VSCHEMA TABLES", 172 expected, 173 100*time.Millisecond, 174 3*time.Second, 175 "initial table list not complete") 176 177 // Init 178 _ = utils.Exec(t, conn, "create table test_sc (id bigint primary key)") 179 expected = `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")]]` 180 if vtgateVersion >= 17 { 181 expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")]]` 182 } 183 utils.AssertMatchesWithTimeout(t, conn, 184 "SHOW VSCHEMA TABLES", 185 expected, 186 100*time.Millisecond, 187 3*time.Second, 188 "test_sc not in vschema tables") 189 190 // Tables Update via health check. 191 _ = utils.Exec(t, conn, "create table test_sc1 (id bigint primary key)") 192 expected = `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")] [VARCHAR("test_sc1")]]` 193 if vtgateVersion >= 17 { 194 expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")] [VARCHAR("test_sc1")]]` 195 } 196 utils.AssertMatchesWithTimeout(t, conn, 197 "SHOW VSCHEMA TABLES", 198 expected, 199 100*time.Millisecond, 200 3*time.Second, 201 "test_sc1 not in vschema tables") 202 203 _ = utils.Exec(t, conn, "drop table test_sc, test_sc1") 204 expected = `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]` 205 if vtgateVersion >= 17 { 206 expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]` 207 } 208 utils.AssertMatchesWithTimeout(t, conn, 209 "SHOW VSCHEMA TABLES", 210 expected, 211 100*time.Millisecond, 212 3*time.Second, 213 "test_sc and test_sc_1 should not be in vschema tables") 214 215 } 216 217 func TestDMLOnNewTable(t *testing.T) { 218 ctx := context.Background() 219 conn, err := mysql.Connect(ctx, &vtParams) 220 require.NoError(t, err) 221 defer conn.Close() 222 223 // create a new table which is not part of the VSchema 224 utils.Exec(t, conn, `create table new_table_tracked(id bigint, name varchar(100), primary key(id)) Engine=InnoDB`) 225 226 vtgateVersion, err := cluster.GetMajorVersion("vtgate") 227 require.NoError(t, err) 228 expected := `[[VARCHAR("dual")] [VARCHAR("new_table_tracked")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]` 229 if vtgateVersion >= 17 { 230 expected = `[[VARCHAR("new_table_tracked")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]` 231 } 232 // wait for vttablet's schema reload interval to pass 233 utils.AssertMatchesWithTimeout(t, conn, 234 "SHOW VSCHEMA TABLES", 235 expected, 236 100*time.Millisecond, 237 3*time.Second, 238 "test_sc not in vschema tables") 239 240 utils.AssertMatches(t, conn, "select id from new_table_tracked", `[]`) // select 241 utils.AssertMatches(t, conn, "select id from new_table_tracked where id = 5", `[]`) // select 242 // DML on new table 243 // insert initial data ,update and delete will fail since we have not added a primary vindex 244 errorMessage := "table 'new_table_tracked' does not have a primary vindex (errno 1173) (sqlstate 42000)" 245 utils.AssertContainsError(t, conn, `insert into new_table_tracked(id) values(0),(1)`, errorMessage) 246 utils.AssertContainsError(t, conn, `update new_table_tracked set name = "newName1"`, errorMessage) 247 utils.AssertContainsError(t, conn, "delete from new_table_tracked", errorMessage) 248 249 utils.Exec(t, conn, `select name from new_table_tracked join t8`) 250 251 // add a primary vindex for the table 252 utils.Exec(t, conn, "alter vschema on ks.new_table_tracked add vindex hash(id) using hash") 253 time.Sleep(1 * time.Second) 254 utils.Exec(t, conn, `insert into new_table_tracked(id) values(0),(1)`) 255 utils.Exec(t, conn, `insert into t8(id8) values(2)`) 256 defer utils.Exec(t, conn, `delete from t8`) 257 utils.AssertMatchesNoOrder(t, conn, `select id from new_table_tracked join t8`, `[[INT64(0)] [INT64(1)]]`) 258 } 259 260 // TestNewView validates that view tracking works as expected. 261 func TestNewView(t *testing.T) { 262 utils.SkipIfBinaryIsBelowVersion(t, 16, "vtgate") 263 utils.SkipIfBinaryIsBelowVersion(t, 16, "vttablet") 264 265 ctx := context.Background() 266 conn, err := mysql.Connect(ctx, &vtParams) 267 require.NoError(t, err) 268 defer conn.Close() 269 270 // insert some data 271 _ = utils.Exec(t, conn, "insert into t2 (id3, id4) values (1, 10), (2, 20), (3, 30)") 272 defer utils.Exec(t, conn, "delete from t2") 273 274 selQuery := "select sum(id4) from t2 where id4 > 10" 275 276 // create a view 277 _ = utils.Exec(t, conn, "create view test_view as "+selQuery) 278 279 // executing the query directly 280 qr := utils.Exec(t, conn, selQuery) 281 // selecting it through the view. 282 utils.AssertMatchesWithTimeout(t, conn, "select * from test_view", fmt.Sprintf("%v", qr.Rows), 100*time.Millisecond, 10*time.Second, "test_view not in vschema tables") 283 } 284 285 // TestViewAndTable validates that new column added in table is present in the view definition 286 func TestViewAndTable(t *testing.T) { 287 utils.SkipIfBinaryIsBelowVersion(t, 16, "vtgate") 288 utils.SkipIfBinaryIsBelowVersion(t, 16, "vttablet") 289 290 ctx := context.Background() 291 conn, err := mysql.Connect(ctx, &vtParams) 292 require.NoError(t, err) 293 defer conn.Close() 294 295 // add a new column to the table t8 296 _ = utils.Exec(t, conn, "alter table t8 add column new_col varchar(50)") 297 err = utils.WaitForColumn(t, clusterInstance.VtgateProcess, KeyspaceName, "t8", "new_col") 298 require.NoError(t, err) 299 300 // insert some data 301 _ = utils.Exec(t, conn, "insert into t8(id8, new_col) values (1, 'V')") 302 defer utils.Exec(t, conn, "delete from t8") 303 304 // create a view with t8, having the new column. 305 _ = utils.Exec(t, conn, "create view t8_view as select * from t8") 306 307 // executing the view query, with the new column in the select field. 308 utils.AssertMatchesWithTimeout(t, conn, "select new_col from t8_view", `[[VARCHAR("V")]]`, 100*time.Millisecond, 5*time.Second, "t8_view not in vschema tables") 309 310 // add another column to the table t8 311 _ = utils.Exec(t, conn, "alter table t8 add column additional_col bigint") 312 err = utils.WaitForColumn(t, clusterInstance.VtgateProcess, KeyspaceName, "t8", "additional_col") 313 require.NoError(t, err) 314 315 // executing the query on view 316 qr := utils.Exec(t, conn, "select * from t8_view") 317 // validate that field name should not have additional_col 318 assert.NotContains(t, fmt.Sprintf("%v", qr.Fields), "additional_col") 319 }