vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/vstreamer/testenv/testenv.go (about) 1 /* 2 Copyright 2019 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 testenv supplies test functions for testing vstreamer. 18 package testenv 19 20 import ( 21 "context" 22 "fmt" 23 "os" 24 "regexp" 25 "strconv" 26 "strings" 27 28 "vitess.io/vitess/go/json2" 29 "vitess.io/vitess/go/vt/dbconfigs" 30 "vitess.io/vitess/go/vt/mysqlctl" 31 "vitess.io/vitess/go/vt/srvtopo" 32 "vitess.io/vitess/go/vt/topo" 33 "vitess.io/vitess/go/vt/topo/memorytopo" 34 "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" 35 "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" 36 "vitess.io/vitess/go/vt/vttest" 37 38 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 39 vschemapb "vitess.io/vitess/go/vt/proto/vschema" 40 vttestpb "vitess.io/vitess/go/vt/proto/vttest" 41 ) 42 43 // Env contains all the env vars for a test against a mysql instance. 44 type Env struct { 45 cluster *vttest.LocalCluster 46 47 KeyspaceName string 48 ShardName string 49 Cells []string 50 51 TabletEnv tabletenv.Env 52 TopoServ *topo.Server 53 SrvTopo srvtopo.Server 54 Dbcfgs *dbconfigs.DBConfigs 55 Mysqld *mysqlctl.Mysqld 56 SchemaEngine *schema.Engine 57 Flavor string 58 // MySQL and Percona are considered equivalent here and both called mysql 59 DBType string 60 DBMajorVersion int 61 DBMinorVersion int 62 DBPatchVersion int 63 } 64 65 // Init initializes an Env. 66 func Init() (*Env, error) { 67 te := &Env{ 68 KeyspaceName: "vttest", 69 ShardName: "0", 70 Cells: []string{"cell1"}, 71 } 72 73 ctx := context.Background() 74 te.TopoServ = memorytopo.NewServer(te.Cells...) 75 if err := te.TopoServ.CreateKeyspace(ctx, te.KeyspaceName, &topodatapb.Keyspace{}); err != nil { 76 return nil, err 77 } 78 if err := te.TopoServ.CreateShard(ctx, te.KeyspaceName, te.ShardName); err != nil { 79 panic(err) 80 } 81 te.SrvTopo = srvtopo.NewResilientServer(te.TopoServ, "TestTopo") 82 83 cfg := vttest.Config{ 84 Topology: &vttestpb.VTTestTopology{ 85 Keyspaces: []*vttestpb.Keyspace{ 86 { 87 Name: te.KeyspaceName, 88 Shards: []*vttestpb.Shard{ 89 { 90 Name: "0", 91 DbNameOverride: "vttest", 92 }, 93 }, 94 }, 95 }, 96 }, 97 OnlyMySQL: true, 98 Charset: "utf8mb4_general_ci", 99 } 100 te.cluster = &vttest.LocalCluster{ 101 Config: cfg, 102 } 103 if err := te.cluster.Setup(); err != nil { 104 os.RemoveAll(te.cluster.Config.SchemaDir) 105 return nil, fmt.Errorf("could not launch mysql: %v", err) 106 } 107 te.Dbcfgs = dbconfigs.NewTestDBConfigs(te.cluster.MySQLConnParams(), te.cluster.MySQLAppDebugConnParams(), te.cluster.DbName()) 108 config := tabletenv.NewDefaultConfig() 109 config.DB = te.Dbcfgs 110 te.TabletEnv = tabletenv.NewEnv(config, "VStreamerTest") 111 te.Mysqld = mysqlctl.NewMysqld(te.Dbcfgs) 112 pos, _ := te.Mysqld.PrimaryPosition() 113 te.Flavor = pos.GTIDSet.Flavor() 114 if strings.HasPrefix(strings.ToLower(te.Flavor), string(mysqlctl.FlavorMariaDB)) { 115 te.DBType = string(mysqlctl.FlavorMariaDB) 116 } else { 117 // MySQL and Percona are equivalent for the tests 118 te.DBType = string(mysqlctl.FlavorMySQL) 119 } 120 dbVersionStr := te.Mysqld.GetVersionString() 121 dbVersionStrParts := strings.Split(dbVersionStr, ".") 122 var err error 123 te.DBMajorVersion, err = strconv.Atoi(dbVersionStrParts[0]) 124 if err != nil { 125 return nil, fmt.Errorf("could not parse database major version from '%s': %v", dbVersionStr, err) 126 } 127 te.DBMinorVersion, err = strconv.Atoi(dbVersionStrParts[1]) 128 if err != nil { 129 return nil, fmt.Errorf("could not parse database minor version from '%s': %v", dbVersionStr, err) 130 } 131 te.DBPatchVersion, err = strconv.Atoi(dbVersionStrParts[2]) 132 if err != nil { 133 return nil, fmt.Errorf("could not parse database patch version from '%s': %v", dbVersionStr, err) 134 } 135 136 te.SchemaEngine = schema.NewEngine(te.TabletEnv) 137 te.SchemaEngine.InitDBConfig(te.Dbcfgs.DbaWithDB()) 138 if err := te.SchemaEngine.Open(); err != nil { 139 return nil, err 140 } 141 142 // The first vschema should not be empty. Leads to Node not found error. 143 // TODO(sougou): need to fix the bug. 144 if err := te.SetVSchema(`{"sharded": true}`); err != nil { 145 te.Close() 146 return nil, err 147 } 148 149 return te, nil 150 } 151 152 // Close tears down TestEnv. 153 func (te *Env) Close() { 154 te.SchemaEngine.Close() 155 te.Mysqld.Close() 156 te.cluster.TearDown() 157 os.RemoveAll(te.cluster.Config.SchemaDir) 158 } 159 160 // SetVSchema sets the vschema for the test keyspace. 161 func (te *Env) SetVSchema(vs string) error { 162 ctx := context.Background() 163 var kspb vschemapb.Keyspace 164 if err := json2.Unmarshal([]byte(vs), &kspb); err != nil { 165 return err 166 } 167 if err := te.TopoServ.SaveVSchema(ctx, te.KeyspaceName, &kspb); err != nil { 168 return err 169 } 170 te.SchemaEngine.Reload(ctx) 171 return te.TopoServ.RebuildSrvVSchema(ctx, te.Cells) 172 } 173 174 // In MySQL 8.0 and later information_schema no longer contains the display width for integer types and 175 // as of 8.0.19 for year types as this was an unnecessary headache because it can only serve to confuse 176 // if the display width is less than the type width (8.0 no longer supports the 2 digit YEAR). So if the 177 // test is running against MySQL 8.0 or later then you should use this function to replace e.g. 178 // `int([0-9]*)` with `int` in the expected results string that we define in the test. 179 func (te *Env) RemoveAnyDeprecatedDisplayWidths(orig string) string { 180 if te.DBType != string(mysqlctl.FlavorMySQL) || te.DBMajorVersion < 8 { 181 return orig 182 } 183 var adjusted string 184 baseIntType := "int" 185 intRE := regexp.MustCompile(`(?i)int\(([0-9]*)?\)`) 186 adjusted = intRE.ReplaceAllString(orig, baseIntType) 187 if (te.DBMajorVersion > 8 || te.DBMinorVersion > 0) || te.DBPatchVersion >= 19 { 188 baseYearType := "year" 189 yearRE := regexp.MustCompile(`(?i)year\(([0-9]*)?\)`) 190 adjusted = yearRE.ReplaceAllString(adjusted, baseYearType) 191 } 192 return adjusted 193 }