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  }