vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/schema/tracker_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 schema 18 19 import ( 20 "testing" 21 22 "github.com/stretchr/testify/require" 23 24 "context" 25 26 "vitess.io/vitess/go/sqltypes" 27 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 28 "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" 29 ) 30 31 func TestTracker(t *testing.T) { 32 initialSchemaInserted := false 33 se, db, cancel := getTestSchemaEngine(t) 34 defer cancel() 35 gtid1 := "MySQL56/7b04699f-f5e9-11e9-bf88-9cb6d089e1c3:1-10" 36 ddl1 := "create table tracker_test (id int)" 37 query := "CREATE TABLE IF NOT EXISTS _vt.schema_version.*" 38 db.AddQueryPattern(query, &sqltypes.Result{}) 39 40 db.AddQueryPattern("insert into _vt.schema_version.*1-10.*", &sqltypes.Result{}) 41 db.AddQueryPatternWithCallback("insert into _vt.schema_version.*1-3.*", &sqltypes.Result{}, func(query string) { 42 initialSchemaInserted = true 43 }) 44 // simulates empty schema_version table, so initial schema should be inserted 45 db.AddQuery("select id from _vt.schema_version limit 1", &sqltypes.Result{Rows: [][]sqltypes.Value{}}) 46 // called to get current position 47 db.AddQuery("SELECT @@GLOBAL.gtid_executed", sqltypes.MakeTestResult(sqltypes.MakeTestFields( 48 "", 49 "varchar"), 50 "7b04699f-f5e9-11e9-bf88-9cb6d089e1c3:1-3", 51 )) 52 vs := &fakeVstreamer{ 53 done: make(chan struct{}), 54 events: [][]*binlogdatapb.VEvent{{ 55 { 56 Type: binlogdatapb.VEventType_GTID, 57 Gtid: gtid1, 58 }, { 59 Type: binlogdatapb.VEventType_DDL, 60 Statement: ddl1, 61 }, 62 { 63 Type: binlogdatapb.VEventType_GTID, 64 Statement: "", // This event should cause an error updating schema since gtid is bad 65 }, { 66 Type: binlogdatapb.VEventType_DDL, 67 Statement: ddl1, 68 }, 69 { 70 Type: binlogdatapb.VEventType_GTID, 71 Gtid: gtid1, 72 }, { 73 Type: binlogdatapb.VEventType_DDL, 74 Statement: "", 75 }, 76 }}, 77 } 78 config := se.env.Config() 79 config.TrackSchemaVersions = true 80 env := tabletenv.NewEnv(config, "TrackerTest") 81 initial := env.Stats().ErrorCounters.Counts()["INTERNAL"] 82 tracker := NewTracker(env, vs, se) 83 tracker.Open() 84 <-vs.done 85 cancel() 86 tracker.Close() 87 final := env.Stats().ErrorCounters.Counts()["INTERNAL"] 88 require.Equal(t, initial+1, final) 89 require.True(t, initialSchemaInserted) 90 } 91 92 func TestTrackerShouldNotInsertInitialSchema(t *testing.T) { 93 initialSchemaInserted := false 94 se, db, cancel := getTestSchemaEngine(t) 95 gtid1 := "MySQL56/7b04699f-f5e9-11e9-bf88-9cb6d089e1c3:1-10" 96 97 defer cancel() 98 // simulates existing rows in schema_version, so initial schema should not be inserted 99 db.AddQuery("select id from _vt.schema_version limit 1", sqltypes.MakeTestResult(sqltypes.MakeTestFields( 100 "id", 101 "int"), 102 "1", 103 )) 104 // called to get current position 105 db.AddQuery("SELECT @@GLOBAL.gtid_executed", sqltypes.MakeTestResult(sqltypes.MakeTestFields( 106 "", 107 "varchar"), 108 "7b04699f-f5e9-11e9-bf88-9cb6d089e1c3:1-3", 109 )) 110 db.AddQueryPatternWithCallback("insert into _vt.schema_version.*1-3.*", &sqltypes.Result{}, func(query string) { 111 initialSchemaInserted = true 112 }) 113 vs := &fakeVstreamer{ 114 done: make(chan struct{}), 115 events: [][]*binlogdatapb.VEvent{{ 116 { 117 Type: binlogdatapb.VEventType_GTID, 118 Gtid: gtid1, 119 }, 120 }}, 121 } 122 config := se.env.Config() 123 config.TrackSchemaVersions = true 124 env := tabletenv.NewEnv(config, "TrackerTest") 125 tracker := NewTracker(env, vs, se) 126 tracker.Open() 127 <-vs.done 128 cancel() 129 tracker.Close() 130 require.False(t, initialSchemaInserted) 131 } 132 133 var _ VStreamer = (*fakeVstreamer)(nil) 134 135 type fakeVstreamer struct { 136 done chan struct{} 137 events [][]*binlogdatapb.VEvent 138 } 139 140 func (f *fakeVstreamer) Stream(ctx context.Context, startPos string, tablePKs []*binlogdatapb.TableLastPK, filter *binlogdatapb.Filter, send func([]*binlogdatapb.VEvent) error) error { 141 for _, events := range f.events { 142 err := send(events) 143 if err != nil { 144 return err 145 } 146 } 147 close(f.done) 148 <-ctx.Done() 149 return nil 150 } 151 152 func TestMustReloadSchemaOnDDL(t *testing.T) { 153 type testcase struct { 154 query string 155 dbname string 156 want bool 157 } 158 db1, db2 := "db1", "db2" 159 testcases := []*testcase{ 160 {"create table x(i int);", db1, true}, 161 {"bad", db2, false}, 162 {"create table db2.x(i int);", db2, true}, 163 {"rename table db2.x to db2.y;", db2, true}, 164 {"create table db1.x(i int);", db2, false}, 165 {"create table _vt.x(i int);", db1, false}, 166 {"DROP VIEW IF EXISTS `pseudo_gtid`.`_pseudo_gtid_hint__asc:55B364E3:0000000000056EE2:6DD57B85`", db2, false}, 167 {"create database db1;", db1, false}, 168 {"create table db1._4e5dcf80_354b_11eb_82cd_f875a4d24e90_20201203114014_gho(i int);", db1, false}, 169 } 170 for _, tc := range testcases { 171 t.Run("", func(t *testing.T) { 172 require.Equal(t, tc.want, MustReloadSchemaOnDDL(tc.query, tc.dbname)) 173 }) 174 } 175 }