vitess.io/vitess@v0.16.2/go/vt/vttablet/endtoend/vstreamer_test.go (about) 1 /* 2 Copyright 2020 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 endtoend 18 19 import ( 20 "bytes" 21 "context" 22 "errors" 23 "fmt" 24 "strings" 25 "testing" 26 "time" 27 28 "vitess.io/vitess/go/sqltypes" 29 "vitess.io/vitess/go/vt/log" 30 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 31 querypb "vitess.io/vitess/go/vt/proto/query" 32 tabletpb "vitess.io/vitess/go/vt/proto/topodata" 33 "vitess.io/vitess/go/vt/vttablet/endtoend/framework" 34 ) 35 36 type test struct { 37 query string 38 output []string 39 } 40 41 // the schema version tests can get events related to the creation of the schema version table depending on 42 // whether the table already exists or not. To avoid different behaviour when tests are run together 43 // this function adds to events expected if table is not present 44 func getSchemaVersionTableCreationEvents() []string { 45 tableCreationEvents := []string{"gtid", "other", "gtid", "other", "gtid", "other"} 46 client := framework.NewClient() 47 _, err := client.Execute("describe _vt.schema_version", nil) 48 if err != nil { 49 log.Errorf("_vt.schema_version not found, will expect its table creation events") 50 return tableCreationEvents 51 } 52 return nil 53 } 54 55 func TestSchemaVersioning(t *testing.T) { 56 // Let's disable the already running tracker to prevent it from 57 // picking events from the previous test, and then re-enable it at the end. 58 tsv := framework.Server 59 tsv.EnableHistorian(false) 60 tsv.SetTracking(false) 61 tsv.EnableHeartbeat(false) 62 tsv.EnableThrottler(false) 63 defer tsv.EnableThrottler(true) 64 defer tsv.EnableHeartbeat(true) 65 defer tsv.EnableHistorian(true) 66 defer tsv.SetTracking(true) 67 68 ctx, cancel := context.WithCancel(context.Background()) 69 defer cancel() 70 tsv.EnableHistorian(true) 71 tsv.SetTracking(true) 72 time.Sleep(100 * time.Millisecond) // wait for _vt tables to be created 73 target := &querypb.Target{ 74 Keyspace: "vttest", 75 Shard: "0", 76 TabletType: tabletpb.TabletType_PRIMARY, 77 Cell: "", 78 } 79 filter := &binlogdatapb.Filter{ 80 Rules: []*binlogdatapb.Rule{{ 81 Match: "/.*/", 82 }}, 83 } 84 85 var cases = []test{ 86 { 87 query: "create table vitess_version (\n\tid1 int,\n\tid2 int\n)", 88 output: append(append([]string{ 89 `gtid`, //gtid+other => vstream current pos 90 `other`, 91 `gtid`, //gtid+ddl => actual query 92 `type:DDL statement:"create table vitess_version (\n\tid1 int,\n\tid2 int\n)"`}, 93 getSchemaVersionTableCreationEvents()...), 94 `version`, 95 `gtid`, 96 ), 97 }, 98 { 99 query: "insert into vitess_version values(1, 10)", 100 output: []string{ 101 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"}}`, 102 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 values:"110"}}}`, 103 `gtid`, 104 }, 105 }, { 106 query: "alter table vitess_version add column id3 int", 107 output: []string{ 108 `gtid`, 109 `type:DDL statement:"alter table vitess_version add column id3 int"`, 110 `version`, 111 `gtid`, 112 }, 113 }, { 114 query: "insert into vitess_version values(2, 20, 200)", 115 output: []string{ 116 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"} fields:{name:"id3" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:11 charset:63 column_type:"int"}}`, 117 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"220200"}}}`, 118 `gtid`, 119 }, 120 }, { 121 query: "alter table vitess_version modify column id3 varbinary(16)", 122 output: []string{ 123 `gtid`, 124 `type:DDL statement:"alter table vitess_version modify column id3 varbinary(16)"`, 125 `version`, 126 `gtid`, 127 }, 128 }, { 129 query: "insert into vitess_version values(3, 30, 'TTT')", 130 output: []string{ 131 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"}}`, 132 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"330TTT"}}}`, 133 `gtid`, 134 }, 135 }, 136 } 137 eventCh := make(chan []*binlogdatapb.VEvent) 138 var startPos string 139 send := func(events []*binlogdatapb.VEvent) error { 140 var evs []*binlogdatapb.VEvent 141 for _, event := range events { 142 if event.Type == binlogdatapb.VEventType_GTID { 143 if startPos == "" { 144 startPos = event.Gtid 145 } 146 } 147 if event.Type == binlogdatapb.VEventType_HEARTBEAT { 148 continue 149 } 150 log.Infof("Received event %v", event) 151 evs = append(evs, event) 152 } 153 select { 154 case eventCh <- evs: 155 case <-ctx.Done(): 156 return nil 157 } 158 return nil 159 } 160 go func() { 161 defer close(eventCh) 162 req := &binlogdatapb.VStreamRequest{Target: target, Position: "current", TableLastPKs: nil, Filter: filter} 163 if err := tsv.VStream(ctx, req, send); err != nil { 164 fmt.Printf("Error in tsv.VStream: %v", err) 165 t.Error(err) 166 } 167 }() 168 log.Infof("\n\n\n=============================================== CURRENT EVENTS START HERE ======================\n\n\n") 169 runCases(ctx, t, cases, eventCh) 170 171 tsv.SetTracking(false) 172 cases = []test{ 173 { 174 //comment prefix required so we don't look for ddl in schema_version 175 query: "/**/alter table vitess_version add column id4 varbinary(16)", 176 output: []string{ 177 `gtid`, //no tracker, so no insert into schema_version or version event 178 `type:DDL statement:"/**/alter table vitess_version add column id4 varbinary(16)"`, 179 }, 180 }, { 181 query: "insert into vitess_version values(4, 40, 'FFF', 'GGGG' )", 182 output: []string{ 183 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"} fields:{name:"id4" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id4" column_length:16 charset:63 column_type:"varbinary(16)"}}`, 184 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 lengths:4 values:"440FFFGGGG"}}}`, 185 `gtid`, 186 }, 187 }, 188 } 189 runCases(ctx, t, cases, eventCh) 190 cancel() 191 192 log.Infof("\n\n\n=============================================== PAST EVENTS WITH TRACK VERSIONS START HERE ======================\n\n\n") 193 ctx, cancel = context.WithCancel(context.Background()) 194 defer cancel() 195 eventCh = make(chan []*binlogdatapb.VEvent) 196 send = func(events []*binlogdatapb.VEvent) error { 197 var evs []*binlogdatapb.VEvent 198 for _, event := range events { 199 if event.Type == binlogdatapb.VEventType_HEARTBEAT { 200 continue 201 } 202 log.Infof("Received event %v", event) 203 evs = append(evs, event) 204 } 205 select { 206 case eventCh <- evs: 207 case <-ctx.Done(): 208 t.Fatal("Context Done() in send") 209 } 210 return nil 211 } 212 go func() { 213 defer close(eventCh) 214 req := &binlogdatapb.VStreamRequest{Target: target, Position: startPos, TableLastPKs: nil, Filter: filter} 215 if err := tsv.VStream(ctx, req, send); err != nil { 216 fmt.Printf("Error in tsv.VStream: %v", err) 217 t.Error(err) 218 } 219 }() 220 221 // playing events from the past: same events as original since historian is providing the latest schema 222 output := append(append([]string{ 223 `gtid`, 224 `type:DDL statement:"create table vitess_version (\n\tid1 int,\n\tid2 int\n)"`}, 225 getSchemaVersionTableCreationEvents()...), 226 `version`, 227 `gtid`, 228 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"}}`, 229 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 values:"110"}}}`, 230 `gtid`, 231 `gtid`, 232 `type:DDL statement:"alter table vitess_version add column id3 int"`, 233 `version`, 234 `gtid`, 235 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"} fields:{name:"id3" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:11 charset:63 column_type:"varbinary(16)"}}`, 236 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"220200"}}}`, 237 `gtid`, 238 `gtid`, 239 `type:DDL statement:"alter table vitess_version modify column id3 varbinary(16)"`, 240 `version`, 241 `gtid`, 242 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"}}`, 243 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"330TTT"}}}`, 244 `gtid`, 245 `gtid`, 246 `type:DDL statement:"/**/alter table vitess_version add column id4 varbinary(16)"`, 247 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"} fields:{name:"id4" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id4" column_length:16 charset:63 column_type:"varbinary(16)"}}`, 248 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 lengths:4 values:"440FFFGGGG"}}}`, 249 `gtid`, 250 ) 251 252 expectLogs(ctx, t, "Past stream", eventCh, output) 253 254 cancel() 255 256 log.Infof("\n\n\n=============================================== PAST EVENTS WITHOUT TRACK VERSIONS START HERE ======================\n\n\n") 257 tsv.EnableHistorian(false) 258 ctx, cancel = context.WithCancel(context.Background()) 259 defer cancel() 260 eventCh = make(chan []*binlogdatapb.VEvent) 261 send = func(events []*binlogdatapb.VEvent) error { 262 var evs []*binlogdatapb.VEvent 263 for _, event := range events { 264 if event.Type == binlogdatapb.VEventType_HEARTBEAT { 265 continue 266 } 267 log.Infof("Received event %v", event) 268 evs = append(evs, event) 269 } 270 select { 271 case eventCh <- evs: 272 case <-ctx.Done(): 273 t.Fatal("Context Done() in send") 274 } 275 return nil 276 } 277 go func() { 278 defer close(eventCh) 279 req := &binlogdatapb.VStreamRequest{Target: target, Position: startPos, TableLastPKs: nil, Filter: filter} 280 if err := tsv.VStream(ctx, req, send); err != nil { 281 fmt.Printf("Error in tsv.VStream: %v", err) 282 t.Error(err) 283 } 284 }() 285 286 // playing events from the past: same as earlier except one below, see comments 287 output = append(append([]string{ 288 `gtid`, 289 `type:DDL statement:"create table vitess_version (\n\tid1 int,\n\tid2 int\n)"`}, 290 getSchemaVersionTableCreationEvents()...), 291 `version`, 292 `gtid`, 293 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"}}`, 294 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 values:"110"}}}`, 295 `gtid`, 296 `gtid`, 297 `type:DDL statement:"alter table vitess_version add column id3 int"`, 298 `version`, 299 `gtid`, 300 /*at this point we only have latest schema so we have types (int32, int32, varbinary, varbinary) so the types don't match. Hence the @ fieldnames*/ 301 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"@1" type:INT32} fields:{name:"@2" type:INT32} fields:{name:"@3" type:INT32}}`, 302 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"220200"}}}`, 303 `gtid`, 304 `gtid`, 305 `type:DDL statement:"alter table vitess_version modify column id3 varbinary(16)"`, 306 `version`, 307 `gtid`, 308 /*at this point we only have latest schema so we have types (int32, int32, varbinary, varbinary), 309 but the three fields below match the first three types in the latest, so the field names are correct*/ 310 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"}}`, 311 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 values:"330TTT"}}}`, 312 `gtid`, 313 `gtid`, 314 `type:DDL statement:"/**/alter table vitess_version add column id4 varbinary(16)"`, 315 `type:FIELD field_event:{table_name:"vitess_version" fields:{name:"id1" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id1" column_length:11 charset:63 column_type:"int"} fields:{name:"id2" type:INT32 table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id2" column_length:11 charset:63 column_type:"int"} fields:{name:"id3" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id3" column_length:16 charset:63 column_type:"varbinary(16)"} fields:{name:"id4" type:VARBINARY table:"vitess_version" org_table:"vitess_version" database:"vttest" org_name:"id4" column_length:16 charset:63 column_type:"varbinary(16)"}}`, 316 `type:ROW row_event:{table_name:"vitess_version" row_changes:{after:{lengths:1 lengths:2 lengths:3 lengths:4 values:"440FFFGGGG"}}}`, 317 `gtid`, 318 ) 319 320 expectLogs(ctx, t, "Past stream", eventCh, output) 321 cancel() 322 323 client := framework.NewClient() 324 client.Execute("drop table vitess_version", nil) 325 client.Execute("drop table _vt.schema_version", nil) 326 327 log.Info("=== END OF TEST") 328 } 329 330 func runCases(ctx context.Context, t *testing.T, tests []test, eventCh chan []*binlogdatapb.VEvent) { 331 t.Helper() 332 client := framework.NewClient() 333 334 for _, test := range tests { 335 query := test.query 336 client.Execute(query, nil) 337 if len(test.output) > 0 { 338 expectLogs(ctx, t, query, eventCh, test.output) 339 } 340 if strings.HasPrefix(query, "create") || strings.HasPrefix(query, "alter") || strings.HasPrefix(query, "drop") { 341 ok, err := waitForVersionInsert(client, query) 342 if err != nil || !ok { 343 t.Fatalf("Query %s never got inserted into the schema_version table", query) 344 } 345 framework.Server.SchemaEngine().Reload(ctx) 346 347 } 348 } 349 } 350 351 func expectLogs(ctx context.Context, t *testing.T, query string, eventCh chan []*binlogdatapb.VEvent, output []string) { 352 t.Helper() 353 timer := time.NewTimer(5 * time.Second) 354 defer timer.Stop() 355 var evs []*binlogdatapb.VEvent 356 log.Infof("In expectLogs for query %s, output len %d", query, len(output)) 357 for { 358 select { 359 case allevs, ok := <-eventCh: 360 if !ok { 361 t.Fatal("expectLogs: not ok, stream ended early") 362 } 363 // Ignore unrelated gtid progress events that can race with the events that the test expects 364 if len(allevs) == 3 && 365 allevs[0].Type == binlogdatapb.VEventType_BEGIN && 366 allevs[1].Type == binlogdatapb.VEventType_GTID && 367 allevs[2].Type == binlogdatapb.VEventType_COMMIT { 368 continue 369 } 370 for _, ev := range allevs { 371 // Ignore spurious heartbeats that can happen on slow machines. 372 if ev.Type == binlogdatapb.VEventType_HEARTBEAT { 373 continue 374 } 375 if ev.Throttled { 376 continue 377 } 378 // Also ignore begin/commit to reduce list of events to expect, for readability ... 379 if ev.Type == binlogdatapb.VEventType_BEGIN { 380 continue 381 } 382 if ev.Type == binlogdatapb.VEventType_COMMIT { 383 continue 384 } 385 386 evs = append(evs, ev) 387 } 388 log.Infof("In expectLogs, have got %d events, want %d", len(evs), len(output)) 389 case <-ctx.Done(): 390 t.Fatalf("expectLog: Done(), stream ended early") 391 case <-timer.C: 392 t.Fatalf("expectLog: timed out waiting for events: %v: evs\n%v, want\n%v, >> got length %d, wanted length %d", query, evs, output, len(evs), len(output)) 393 } 394 if len(evs) >= len(output) { 395 break 396 } 397 } 398 if len(evs) > len(output) { 399 t.Fatalf("expectLog: got too many events: %v: evs\n%v, want\n%v, >> got length %d, wanted length %d", query, evs, output, len(evs), len(output)) 400 } 401 for i, want := range output { 402 // CurrentTime is not testable. 403 evs[i].CurrentTime = 0 404 switch want { 405 case "begin": 406 if evs[i].Type != binlogdatapb.VEventType_BEGIN { 407 t.Fatalf("%v (%d): event: %v, want begin", query, i, evs[i]) 408 } 409 case "gtid": 410 if evs[i].Type != binlogdatapb.VEventType_GTID { 411 t.Fatalf("%v (%d): event: %v, want gtid", query, i, evs[i]) 412 } 413 case "commit": 414 if evs[i].Type != binlogdatapb.VEventType_COMMIT { 415 t.Fatalf("%v (%d): event: %v, want commit", query, i, evs[i]) 416 } 417 case "other": 418 if evs[i].Type != binlogdatapb.VEventType_OTHER { 419 t.Fatalf("%v (%d): event: %v, want other", query, i, evs[i]) 420 } 421 case "version": 422 if evs[i].Type != binlogdatapb.VEventType_VERSION { 423 t.Fatalf("%v (%d): event: %v, want version", query, i, evs[i]) 424 } 425 default: 426 evs[i].Timestamp = 0 427 evs[i].Keyspace = "" 428 evs[i].Shard = "" 429 if evs[i].Type == binlogdatapb.VEventType_FIELD { 430 for j := range evs[i].FieldEvent.Fields { 431 evs[i].FieldEvent.Fields[j].Flags = 0 432 } 433 evs[i].FieldEvent.Keyspace = "" 434 evs[i].FieldEvent.Shard = "" 435 } 436 if evs[i].Type == binlogdatapb.VEventType_ROW { 437 evs[i].RowEvent.Keyspace = "" 438 evs[i].RowEvent.Shard = "" 439 } 440 if got := fmt.Sprintf("%v", evs[i]); got != want { 441 t.Fatalf("%v (%d): event:\n%q, want\n%q", query, i, got, want) 442 } 443 } 444 } 445 } 446 447 func encodeString(in string) string { 448 buf := bytes.NewBuffer(nil) 449 sqltypes.NewVarChar(in).EncodeSQL(buf) 450 return buf.String() 451 } 452 453 func validateSchemaInserted(client *framework.QueryClient, ddl string) bool { 454 qr, _ := client.Execute(fmt.Sprintf("select * from _vt.schema_version where ddl = %s", encodeString(ddl)), nil) 455 if len(qr.Rows) == 1 { 456 log.Infof("Found ddl in schema_version: %s", ddl) 457 return true 458 } 459 return false 460 } 461 462 // To avoid races between ddls and the historian refreshing its cache explicitly wait for tracker's insert to be visible 463 func waitForVersionInsert(client *framework.QueryClient, ddl string) (bool, error) { 464 timeout := time.After(3000 * time.Millisecond) 465 tick := time.Tick(100 * time.Millisecond) 466 for { 467 select { 468 case <-timeout: 469 log.Infof("waitForVersionInsert timed out") 470 return false, errors.New("waitForVersionInsert timed out") 471 case <-tick: 472 ok := validateSchemaInserted(client, ddl) 473 if ok { 474 log.Infof("Found version insert for %s", ddl) 475 return true, nil 476 } 477 } 478 } 479 }