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  }