github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/restore/client_test.go (about) 1 // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0. 2 3 package restore_test 4 5 import ( 6 "context" 7 "math" 8 "strconv" 9 "time" 10 11 "github.com/pingcap/br/pkg/metautil" 12 13 . "github.com/pingcap/check" 14 "github.com/pingcap/kvproto/pkg/metapb" 15 "github.com/pingcap/parser/model" 16 "github.com/pingcap/parser/mysql" 17 "github.com/pingcap/parser/types" 18 "github.com/pingcap/tidb/tablecodec" 19 "github.com/pingcap/tidb/util/testleak" 20 pd "github.com/tikv/pd/client" 21 "google.golang.org/grpc/keepalive" 22 23 "github.com/pingcap/br/pkg/gluetidb" 24 "github.com/pingcap/br/pkg/mock" 25 "github.com/pingcap/br/pkg/restore" 26 ) 27 28 var _ = Suite(&testRestoreClientSuite{}) 29 30 var defaultKeepaliveCfg = keepalive.ClientParameters{ 31 Time: 3 * time.Second, 32 Timeout: 10 * time.Second, 33 } 34 35 type testRestoreClientSuite struct { 36 mock *mock.Cluster 37 } 38 39 func (s *testRestoreClientSuite) SetUpTest(c *C) { 40 var err error 41 s.mock, err = mock.NewCluster() 42 c.Assert(err, IsNil) 43 } 44 45 func (s *testRestoreClientSuite) TearDownTest(c *C) { 46 testleak.AfterTest(c)() 47 } 48 49 func (s *testRestoreClientSuite) TestCreateTables(c *C) { 50 c.Assert(s.mock.Start(), IsNil) 51 defer s.mock.Stop() 52 client, err := restore.NewRestoreClient(gluetidb.New(), s.mock.PDClient, s.mock.Storage, nil, defaultKeepaliveCfg) 53 c.Assert(err, IsNil) 54 55 info, err := s.mock.Domain.GetSnapshotInfoSchema(math.MaxUint64) 56 c.Assert(err, IsNil) 57 dbSchema, isExist := info.SchemaByName(model.NewCIStr("test")) 58 c.Assert(isExist, IsTrue) 59 60 tables := make([]*metautil.Table, 4) 61 intField := types.NewFieldType(mysql.TypeLong) 62 intField.Charset = "binary" 63 for i := len(tables) - 1; i >= 0; i-- { 64 tables[i] = &metautil.Table{ 65 DB: dbSchema, 66 Info: &model.TableInfo{ 67 ID: int64(i), 68 Name: model.NewCIStr("test" + strconv.Itoa(i)), 69 Columns: []*model.ColumnInfo{{ 70 ID: 1, 71 Name: model.NewCIStr("id"), 72 FieldType: *intField, 73 State: model.StatePublic, 74 }}, 75 Charset: "utf8mb4", 76 Collate: "utf8mb4_bin", 77 }, 78 } 79 } 80 rules, newTables, err := client.CreateTables(s.mock.Domain, tables, 0) 81 c.Assert(err, IsNil) 82 // make sure tables and newTables have same order 83 for i, t := range tables { 84 c.Assert(newTables[i].Name, Equals, t.Info.Name) 85 } 86 for _, nt := range newTables { 87 c.Assert(nt.Name.String(), Matches, "test[0-3]") 88 } 89 oldTableIDExist := make(map[int64]bool) 90 newTableIDExist := make(map[int64]bool) 91 for _, tr := range rules.Data { 92 oldTableID := tablecodec.DecodeTableID(tr.GetOldKeyPrefix()) 93 c.Assert(oldTableIDExist[oldTableID], IsFalse, Commentf("table rule duplicate old table id")) 94 oldTableIDExist[oldTableID] = true 95 96 newTableID := tablecodec.DecodeTableID(tr.GetNewKeyPrefix()) 97 c.Assert(newTableIDExist[newTableID], IsFalse, Commentf("table rule duplicate new table id")) 98 newTableIDExist[newTableID] = true 99 } 100 101 for i := 0; i < len(tables); i++ { 102 c.Assert(oldTableIDExist[int64(i)], IsTrue, Commentf("table rule does not exist")) 103 } 104 } 105 106 func (s *testRestoreClientSuite) TestIsOnline(c *C) { 107 c.Assert(s.mock.Start(), IsNil) 108 defer s.mock.Stop() 109 110 client, err := restore.NewRestoreClient(gluetidb.New(), s.mock.PDClient, s.mock.Storage, nil, defaultKeepaliveCfg) 111 c.Assert(err, IsNil) 112 113 c.Assert(client.IsOnline(), IsFalse) 114 client.EnableOnline() 115 c.Assert(client.IsOnline(), IsTrue) 116 } 117 118 func (s *testRestoreClientSuite) TestPreCheckTableClusterIndex(c *C) { 119 c.Assert(s.mock.Start(), IsNil) 120 defer s.mock.Stop() 121 122 client, err := restore.NewRestoreClient(gluetidb.New(), s.mock.PDClient, s.mock.Storage, nil, defaultKeepaliveCfg) 123 c.Assert(err, IsNil) 124 125 info, err := s.mock.Domain.GetSnapshotInfoSchema(math.MaxUint64) 126 c.Assert(err, IsNil) 127 dbSchema, isExist := info.SchemaByName(model.NewCIStr("test")) 128 c.Assert(isExist, IsTrue) 129 130 tables := make([]*metautil.Table, 4) 131 intField := types.NewFieldType(mysql.TypeLong) 132 intField.Charset = "binary" 133 for i := len(tables) - 1; i >= 0; i-- { 134 tables[i] = &metautil.Table{ 135 DB: dbSchema, 136 Info: &model.TableInfo{ 137 ID: int64(i), 138 Name: model.NewCIStr("test" + strconv.Itoa(i)), 139 Columns: []*model.ColumnInfo{{ 140 ID: 1, 141 Name: model.NewCIStr("id"), 142 FieldType: *intField, 143 State: model.StatePublic, 144 }}, 145 Charset: "utf8mb4", 146 Collate: "utf8mb4_bin", 147 }, 148 } 149 } 150 _, _, err = client.CreateTables(s.mock.Domain, tables, 0) 151 c.Assert(err, IsNil) 152 153 // exist different tables 154 tables[1].Info.IsCommonHandle = true 155 c.Assert(client.PreCheckTableClusterIndex(tables, nil, s.mock.Domain), 156 ErrorMatches, `.*@@tidb_enable_clustered_index should be ON \(backup table = true, created table = false\).*`) 157 158 // exist different DDLs 159 jobs := []*model.Job{{ 160 ID: 5, 161 Type: model.ActionCreateTable, 162 SchemaName: "test", 163 Query: "", 164 BinlogInfo: &model.HistoryInfo{ 165 TableInfo: &model.TableInfo{ 166 Name: model.NewCIStr("test1"), 167 IsCommonHandle: true, 168 }, 169 }, 170 }} 171 c.Assert(client.PreCheckTableClusterIndex(nil, jobs, s.mock.Domain), 172 ErrorMatches, `.*@@tidb_enable_clustered_index should be ON \(backup table = true, created table = false\).*`) 173 174 // should pass pre-check cluster index 175 tables[1].Info.IsCommonHandle = false 176 jobs[0].BinlogInfo.TableInfo.IsCommonHandle = false 177 c.Assert(client.PreCheckTableClusterIndex(tables, jobs, s.mock.Domain), IsNil) 178 } 179 180 type fakePDClient struct { 181 pd.Client 182 stores []*metapb.Store 183 } 184 185 func (fpdc fakePDClient) GetAllStores(context.Context, ...pd.GetStoreOption) ([]*metapb.Store, error) { 186 return append([]*metapb.Store{}, fpdc.stores...), nil 187 } 188 189 func (s *testRestoreClientSuite) TestPreCheckTableTiFlashReplicas(c *C) { 190 c.Assert(s.mock.Start(), IsNil) 191 defer s.mock.Stop() 192 193 mockStores := []*metapb.Store{ 194 { 195 Id: 1, 196 Labels: []*metapb.StoreLabel{ 197 { 198 Key: "engine", 199 Value: "tiflash", 200 }, 201 }, 202 }, 203 { 204 Id: 2, 205 Labels: []*metapb.StoreLabel{ 206 { 207 Key: "engine", 208 Value: "tiflash", 209 }, 210 }, 211 }, 212 } 213 214 client, err := restore.NewRestoreClient(gluetidb.New(), fakePDClient{ 215 stores: mockStores, 216 }, s.mock.Storage, nil, defaultKeepaliveCfg) 217 c.Assert(err, IsNil) 218 219 tables := make([]*metautil.Table, 4) 220 for i := 0; i < len(tables); i++ { 221 tiflashReplica := &model.TiFlashReplicaInfo{ 222 Count: uint64(i), 223 } 224 if i == 0 { 225 tiflashReplica = nil 226 } 227 228 tables[i] = &metautil.Table{ 229 DB: nil, 230 Info: &model.TableInfo{ 231 ID: int64(i), 232 Name: model.NewCIStr("test" + strconv.Itoa(i)), 233 TiFlashReplica: tiflashReplica, 234 }, 235 } 236 } 237 ctx := context.Background() 238 c.Assert(client.PreCheckTableTiFlashReplica(ctx, tables), IsNil) 239 240 for i := 0; i < len(tables); i++ { 241 if i == 0 || i > 2 { 242 c.Assert(tables[i].Info.TiFlashReplica, IsNil) 243 } else { 244 c.Assert(tables[i].Info.TiFlashReplica, NotNil) 245 obtainCount := int(tables[i].Info.TiFlashReplica.Count) 246 c.Assert(obtainCount, Equals, i) 247 } 248 } 249 }