vitess.io/vitess@v0.16.2/go/vt/wrangler/testlib/copy_schema_shard_test.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 testlib 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 "time" 24 25 "vitess.io/vitess/go/vt/discovery" 26 27 "vitess.io/vitess/go/mysql/fakesqldb" 28 "vitess.io/vitess/go/sqltypes" 29 "vitess.io/vitess/go/vt/logutil" 30 "vitess.io/vitess/go/vt/mysqlctl/tmutils" 31 "vitess.io/vitess/go/vt/topo/memorytopo" 32 "vitess.io/vitess/go/vt/topo/topoproto" 33 "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" 34 "vitess.io/vitess/go/vt/vttablet/tmclient" 35 "vitess.io/vitess/go/vt/wrangler" 36 37 tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" 38 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 39 ) 40 41 func TestCopySchemaShard_UseTabletAsSource(t *testing.T) { 42 copySchema(t, false /* useShardAsSource */) 43 } 44 45 func TestCopySchemaShard_UseShardAsSource(t *testing.T) { 46 copySchema(t, true /* useShardAsSource */) 47 } 48 49 func copySchema(t *testing.T, useShardAsSource bool) { 50 delay := discovery.GetTabletPickerRetryDelay() 51 defer func() { 52 discovery.SetTabletPickerRetryDelay(delay) 53 }() 54 discovery.SetTabletPickerRetryDelay(5 * time.Millisecond) 55 56 ts := memorytopo.NewServer("cell1", "cell2") 57 wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient()) 58 vp := NewVtctlPipe(t, ts) 59 defer vp.Close() 60 61 if err := ts.CreateKeyspace(context.Background(), "ks", &topodatapb.Keyspace{}); err != nil { 62 t.Fatalf("CreateKeyspace failed: %v", err) 63 } 64 65 sourcePrimaryDb := fakesqldb.New(t).SetName("sourcePrimaryDb") 66 defer sourcePrimaryDb.Close() 67 sourcePrimary := NewFakeTablet(t, wr, "cell1", 0, 68 topodatapb.TabletType_PRIMARY, sourcePrimaryDb, TabletKeyspaceShard(t, "ks", "-80")) 69 70 sourceRdonlyDb := fakesqldb.New(t).SetName("sourceRdonlyDb") 71 defer sourceRdonlyDb.Close() 72 sourceRdonly := NewFakeTablet(t, wr, "cell1", 1, 73 topodatapb.TabletType_RDONLY, sourceRdonlyDb, TabletKeyspaceShard(t, "ks", "-80")) 74 sourceRdonly.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ 75 // These 4 statements come from tablet startup 76 "STOP SLAVE", 77 "RESET SLAVE ALL", 78 "FAKE SET MASTER", 79 "START SLAVE", 80 } 81 sourceRdonly.FakeMysqlDaemon.SetReplicationSourceInputs = append(sourceRdonly.FakeMysqlDaemon.SetReplicationSourceInputs, fmt.Sprintf("%v:%v", sourcePrimary.Tablet.MysqlHostname, sourcePrimary.Tablet.MysqlPort)) 82 83 destinationPrimaryDb := fakesqldb.New(t).SetName("destinationPrimaryDb") 84 defer destinationPrimaryDb.Close() 85 destinationPrimary := NewFakeTablet(t, wr, "cell1", 10, 86 topodatapb.TabletType_PRIMARY, destinationPrimaryDb, TabletKeyspaceShard(t, "ks", "-40")) 87 88 for _, ft := range []*FakeTablet{sourcePrimary, sourceRdonly, destinationPrimary} { 89 ft.StartActionLoop(t, wr) 90 defer ft.StopActionLoop(t) 91 } 92 93 schema := &tabletmanagerdatapb.SchemaDefinition{ 94 DatabaseSchema: "CREATE DATABASE `{{.DatabaseName}}` /*!40100 DEFAULT CHARACTER SET utf8 */", 95 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{ 96 { 97 Name: "table1", 98 Schema: "CREATE TABLE `table1` (\n `id` bigint(20) NOT NULL AUTO_INCREMENT,\n `msg` varchar(64) DEFAULT NULL,\n `keyspace_id` bigint(20) unsigned NOT NULL,\n PRIMARY KEY (`id`),\n KEY `by_msg` (`msg`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8", 99 Type: tmutils.TableBaseTable, 100 }, 101 { 102 Name: "view1", 103 Schema: "CREATE TABLE `view1` (\n `id` bigint(20) NOT NULL AUTO_INCREMENT,\n `msg` varchar(64) DEFAULT NULL,\n `keyspace_id` bigint(20) unsigned NOT NULL,\n PRIMARY KEY (`id`),\n KEY `by_msg` (`msg`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8", 104 Type: tmutils.TableView, 105 }, 106 }, 107 } 108 schemaEmptyDb := &tabletmanagerdatapb.SchemaDefinition{ 109 DatabaseSchema: "CREATE DATABASE `{{.DatabaseName}}` /*!40100 DEFAULT CHARACTER SET utf8 */", 110 TableDefinitions: []*tabletmanagerdatapb.TableDefinition{}, 111 } 112 sourcePrimary.FakeMysqlDaemon.Schema = schema 113 sourceRdonly.FakeMysqlDaemon.Schema = schema 114 115 setSQLMode := fmt.Sprintf("SET @@session.sql_mode='%v'", vreplication.SQLMode) 116 changeToDb := "USE `vt_ks`" 117 createDb := "CREATE DATABASE `vt_ks` /*!40100 DEFAULT CHARACTER SET utf8 */" 118 createTable := "CREATE TABLE `vt_ks`.`table1` (\n" + 119 " `id` bigint(20) NOT NULL AUTO_INCREMENT,\n" + 120 " `msg` varchar(64) DEFAULT NULL,\n" + 121 " `keyspace_id` bigint(20) unsigned NOT NULL,\n" + 122 " PRIMARY KEY (`id`),\n" + 123 " KEY `by_msg` (`msg`)\n" + 124 ") ENGINE=InnoDB DEFAULT CHARSET=utf8" 125 createTableView := "CREATE TABLE `view1` (\n" + 126 " `id` bigint(20) NOT NULL AUTO_INCREMENT,\n" + 127 " `msg` varchar(64) DEFAULT NULL,\n" + 128 " `keyspace_id` bigint(20) unsigned NOT NULL,\n" + 129 " PRIMARY KEY (`id`),\n" + 130 " KEY `by_msg` (`msg`)\n" + 131 ") ENGINE=InnoDB DEFAULT CHARSET=utf8" 132 133 // The source table is asked about its schema. 134 // It may be the primary or the rdonly. 135 sourceDb := sourceRdonlyDb 136 if useShardAsSource { 137 sourceDb = sourcePrimaryDb 138 } 139 sourceDb.AddQuery(changeToDb, &sqltypes.Result{}) 140 141 // The destination table is asked to create the new schema. 142 destinationPrimaryDb.AddQuery(setSQLMode, &sqltypes.Result{}) 143 destinationPrimaryDb.AddQuery(createDb, &sqltypes.Result{}) 144 destinationPrimaryDb.AddQuery(changeToDb, &sqltypes.Result{}) 145 destinationPrimaryDb.AddQuery(createTable, &sqltypes.Result{}) 146 destinationPrimaryDb.AddQuery(createTableView, &sqltypes.Result{}) 147 148 destinationPrimary.FakeMysqlDaemon.SchemaFunc = func() (*tabletmanagerdatapb.SchemaDefinition, error) { 149 if destinationPrimaryDb.GetQueryCalledNum(createTableView) == 1 { 150 return schema, nil 151 } 152 return schemaEmptyDb, nil 153 } 154 155 source := topoproto.TabletAliasString(sourceRdonly.Tablet.Alias) 156 if useShardAsSource { 157 source = "ks/-80" 158 } 159 if err := vp.Run([]string{"CopySchemaShard", "--include-views", source, "ks/-40"}); err != nil { 160 t.Fatalf("CopySchemaShard failed: %v", err) 161 } 162 163 // Check call count on destinationPrimaryDb 164 if count := destinationPrimaryDb.GetQueryCalledNum(createDb); count != 1 { 165 t.Errorf("CopySchemaShard did not create the db exactly once. Query count: %v", count) 166 } 167 if count := destinationPrimaryDb.GetQueryCalledNum(createTable); count != 1 { 168 t.Errorf("CopySchemaShard did not create the table exactly once. Query count: %v", count) 169 } 170 if count := destinationPrimaryDb.GetQueryCalledNum(createTableView); count != 1 { 171 t.Errorf("CopySchemaShard did not create the table view exactly once. Query count: %v", count) 172 } 173 }