vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/schematracker/restarttablet/schema_restart_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 schematracker 18 19 import ( 20 "context" 21 "encoding/json" 22 "flag" 23 "fmt" 24 "net/http" 25 "os" 26 "testing" 27 "time" 28 29 "vitess.io/vitess/go/test/endtoend/utils" 30 31 "github.com/stretchr/testify/require" 32 33 "github.com/stretchr/testify/assert" 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 hostname = "localhost" 43 keyspaceName = "ks" 44 cell = "zone1" 45 signalInterval = 1 46 sqlSchema = ` 47 create table vt_user ( 48 id bigint, 49 name varchar(64), 50 primary key (id) 51 ) Engine=InnoDB; 52 53 create table main ( 54 id bigint, 55 val varchar(128), 56 primary key(id) 57 ) Engine=InnoDB; 58 59 create table test_table ( 60 id bigint, 61 val varchar(128), 62 primary key(id) 63 ) Engine=InnoDB; 64 ` 65 ) 66 67 func TestMain(m *testing.M) { 68 defer cluster.PanicHandler(nil) 69 flag.Parse() 70 71 exitcode := func() int { 72 clusterInstance = cluster.NewCluster(cell, hostname) 73 defer clusterInstance.Teardown() 74 75 // Start topo server 76 if err := clusterInstance.StartTopo(); err != nil { 77 return 1 78 } 79 80 // List of users authorized to execute vschema ddl operations 81 clusterInstance.VtGateExtraArgs = []string{"--schema_change_signal"} 82 83 // Start keyspace 84 keyspace := &cluster.Keyspace{ 85 Name: keyspaceName, 86 SchemaSQL: sqlSchema, 87 } 88 if err := clusterInstance.StartUnshardedKeyspace(*keyspace, 1, false); err != nil { 89 return 1 90 } 91 92 // restart the tablet so that the schema.Engine gets a chance to start with existing schema 93 tablet := clusterInstance.Keyspaces[0].Shards[0].PrimaryTablet() 94 tablet.VttabletProcess.ExtraArgs = []string{ 95 "--queryserver-config-schema-change-signal", 96 fmt.Sprintf("--queryserver-config-schema-change-signal-interval=%d", signalInterval), 97 } 98 if err := tablet.RestartOnlyTablet(); err != nil { 99 return 1 100 } 101 102 // Start vtgate 103 if err := clusterInstance.StartVtgate(); err != nil { 104 clusterInstance.VtgateProcess = cluster.VtgateProcess{} 105 return 1 106 } 107 vtParams = mysql.ConnParams{ 108 Host: clusterInstance.Hostname, 109 Port: clusterInstance.VtgateMySQLPort, 110 } 111 return m.Run() 112 }() 113 os.Exit(exitcode) 114 } 115 116 func TestVSchemaTrackerInit(t *testing.T) { 117 defer cluster.PanicHandler(t) 118 ctx := context.Background() 119 conn, err := mysql.Connect(ctx, &vtParams) 120 require.NoError(t, err) 121 defer conn.Close() 122 123 qr := utils.Exec(t, conn, "SHOW VSCHEMA TABLES") 124 got := fmt.Sprintf("%v", qr.Rows) 125 want := `[[VARCHAR("dual")] [VARCHAR("main")] [VARCHAR("test_table")] [VARCHAR("vt_user")]]` 126 assert.Equal(t, want, got) 127 } 128 129 // TestVSchemaTrackerKeyspaceReInit tests that the vschema tracker 130 // properly handles primary tablet restarts -- meaning that we maintain 131 // the exact same vschema state as before the restart. 132 func TestVSchemaTrackerKeyspaceReInit(t *testing.T) { 133 defer cluster.PanicHandler(t) 134 135 primaryTablet := clusterInstance.Keyspaces[0].Shards[0].PrimaryTablet() 136 137 // get the vschema prior to the restarts 138 var originalResults any 139 readVSchema(t, &clusterInstance.VtgateProcess, &originalResults) 140 assert.NotNil(t, originalResults) 141 142 // restart the primary tablet so that the vschema gets reloaded for the keyspace 143 for i := 0; i < 5; i++ { 144 err := primaryTablet.VttabletProcess.TearDownWithTimeout(30 * time.Second) 145 require.NoError(t, err) 146 err = primaryTablet.VttabletProcess.Setup() 147 require.NoError(t, err) 148 err = clusterInstance.WaitForTabletsToHealthyInVtgate() 149 require.NoError(t, err) 150 151 utils.TimeoutAction(t, 1*time.Minute, "timeout - could not find the updated vschema in VTGate", func() bool { 152 var newResults any 153 readVSchema(t, &clusterInstance.VtgateProcess, &newResults) 154 return assert.ObjectsAreEqual(originalResults, newResults) 155 }) 156 } 157 } 158 159 func readVSchema(t *testing.T, vtgate *cluster.VtgateProcess, results *any) { 160 httpClient := &http.Client{Timeout: 5 * time.Second} 161 resp, err := httpClient.Get(vtgate.VSchemaURL) 162 require.NoError(t, err) 163 defer resp.Body.Close() 164 assert.Equal(t, 200, resp.StatusCode) 165 json.NewDecoder(resp.Body).Decode(results) 166 }