github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/restore/db_test.go (about) 1 // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0. 2 3 package restore_test 4 5 import ( 6 "context" 7 "encoding/json" 8 "math" 9 "strconv" 10 "testing" 11 12 "github.com/golang/protobuf/proto" 13 backuppb "github.com/pingcap/kvproto/pkg/backup" 14 15 "github.com/pingcap/br/pkg/metautil" 16 "github.com/pingcap/br/pkg/storage" 17 18 . "github.com/pingcap/check" 19 "github.com/pingcap/parser/model" 20 "github.com/pingcap/tidb/meta/autoid" 21 "github.com/pingcap/tidb/util/testkit" 22 "github.com/pingcap/tidb/util/testleak" 23 "github.com/tikv/client-go/v2/oracle" 24 25 "github.com/pingcap/br/pkg/backup" 26 "github.com/pingcap/br/pkg/gluetidb" 27 "github.com/pingcap/br/pkg/mock" 28 "github.com/pingcap/br/pkg/restore" 29 ) 30 31 func TestT(t *testing.T) { 32 TestingT(t) 33 } 34 35 var _ = Suite(&testRestoreSchemaSuite{}) 36 37 type testRestoreSchemaSuite struct { 38 mock *mock.Cluster 39 storage storage.ExternalStorage 40 } 41 42 func (s *testRestoreSchemaSuite) SetUpSuite(c *C) { 43 var err error 44 s.mock, err = mock.NewCluster() 45 c.Assert(err, IsNil) 46 base := c.MkDir() 47 s.storage, err = storage.NewLocalStorage(base) 48 c.Assert(err, IsNil) 49 c.Assert(s.mock.Start(), IsNil) 50 } 51 52 func (s *testRestoreSchemaSuite) TearDownSuite(c *C) { 53 s.mock.Stop() 54 testleak.AfterTest(c)() 55 } 56 57 func (s *testRestoreSchemaSuite) TestRestoreAutoIncID(c *C) { 58 tk := testkit.NewTestKit(c, s.mock.Storage) 59 tk.MustExec("use test") 60 tk.MustExec("set @@sql_mode=''") 61 tk.MustExec("drop table if exists `\"t\"`;") 62 // Test SQL Mode 63 tk.MustExec("create table `\"t\"` (" + 64 "a int not null," + 65 "time timestamp not null default '0000-00-00 00:00:00');", 66 ) 67 tk.MustExec("insert into `\"t\"` values (10, '0000-00-00 00:00:00');") 68 // Query the current AutoIncID 69 autoIncID, err := strconv.ParseUint(tk.MustQuery("admin show `\"t\"` next_row_id").Rows()[0][3].(string), 10, 64) 70 c.Assert(err, IsNil, Commentf("Error query auto inc id: %s", err)) 71 // Get schemas of db and table 72 info, err := s.mock.Domain.GetSnapshotInfoSchema(math.MaxUint64) 73 c.Assert(err, IsNil, Commentf("Error get snapshot info schema: %s", err)) 74 dbInfo, exists := info.SchemaByName(model.NewCIStr("test")) 75 c.Assert(exists, IsTrue, Commentf("Error get db info")) 76 tableInfo, err := info.TableByName(model.NewCIStr("test"), model.NewCIStr("\"t\"")) 77 c.Assert(err, IsNil, Commentf("Error get table info: %s", err)) 78 table := metautil.Table{ 79 Info: tableInfo.Meta(), 80 DB: dbInfo, 81 } 82 // Get the next AutoIncID 83 idAlloc := autoid.NewAllocator(s.mock.Storage, dbInfo.ID, false, autoid.RowIDAllocType) 84 globalAutoID, err := idAlloc.NextGlobalAutoID(table.Info.ID) 85 c.Assert(err, IsNil, Commentf("Error allocate next auto id")) 86 c.Assert(autoIncID, Equals, uint64(globalAutoID)) 87 // Alter AutoIncID to the next AutoIncID + 100 88 table.Info.AutoIncID = globalAutoID + 100 89 db, err := restore.NewDB(gluetidb.New(), s.mock.Storage) 90 c.Assert(err, IsNil, Commentf("Error create DB")) 91 tk.MustExec("drop database if exists test;") 92 // Test empty collate value 93 table.DB.Charset = "utf8mb4" 94 table.DB.Collate = "" 95 err = db.CreateDatabase(context.Background(), table.DB) 96 c.Assert(err, IsNil, Commentf("Error create empty collate db: %s %s", err, s.mock.DSN)) 97 tk.MustExec("drop database if exists test;") 98 // Test empty charset value 99 table.DB.Charset = "" 100 table.DB.Collate = "utf8mb4_bin" 101 err = db.CreateDatabase(context.Background(), table.DB) 102 c.Assert(err, IsNil, Commentf("Error create empty charset db: %s %s", err, s.mock.DSN)) 103 err = db.CreateTable(context.Background(), &table) 104 c.Assert(err, IsNil, Commentf("Error create table: %s %s", err, s.mock.DSN)) 105 tk.MustExec("use test") 106 // Check if AutoIncID is altered successfully 107 autoIncID, err = strconv.ParseUint(tk.MustQuery("admin show `\"t\"` next_row_id").Rows()[0][3].(string), 10, 64) 108 c.Assert(err, IsNil, Commentf("Error query auto inc id: %s", err)) 109 c.Assert(autoIncID, Equals, uint64(globalAutoID+100)) 110 } 111 112 func (s *testRestoreSchemaSuite) TestFilterDDLJobs(c *C) { 113 tk := testkit.NewTestKit(c, s.mock.Storage) 114 tk.MustExec("CREATE DATABASE IF NOT EXISTS test_db;") 115 tk.MustExec("CREATE TABLE IF NOT EXISTS test_db.test_table (c1 INT);") 116 lastTS, err := s.mock.GetOracle().GetTimestamp(context.Background(), &oracle.Option{TxnScope: oracle.GlobalTxnScope}) 117 c.Assert(err, IsNil, Commentf("Error get last ts: %s", err)) 118 tk.MustExec("RENAME TABLE test_db.test_table to test_db.test_table1;") 119 tk.MustExec("DROP TABLE test_db.test_table1;") 120 tk.MustExec("DROP DATABASE test_db;") 121 tk.MustExec("CREATE DATABASE test_db;") 122 tk.MustExec("USE test_db;") 123 tk.MustExec("CREATE TABLE test_table1 (c2 CHAR(255));") 124 tk.MustExec("RENAME TABLE test_table1 to test_table;") 125 tk.MustExec("TRUNCATE TABLE test_table;") 126 127 ts, err := s.mock.GetOracle().GetTimestamp(context.Background(), &oracle.Option{TxnScope: oracle.GlobalTxnScope}) 128 c.Assert(err, IsNil, Commentf("Error get ts: %s", err)) 129 130 metaWriter := metautil.NewMetaWriter(s.storage, metautil.MetaFileSize, false) 131 ctx := context.Background() 132 metaWriter.StartWriteMetasAsync(ctx, metautil.AppendDDL) 133 err = backup.WriteBackupDDLJobs(metaWriter, s.mock.Storage, lastTS, ts) 134 c.Assert(err, IsNil, Commentf("Error get ddl jobs: %s", err)) 135 err = metaWriter.FinishWriteMetas(ctx, metautil.AppendDDL) 136 c.Assert(err, IsNil, Commentf("Flush failed", err)) 137 infoSchema, err := s.mock.Domain.GetSnapshotInfoSchema(ts) 138 c.Assert(err, IsNil, Commentf("Error get snapshot info schema: %s", err)) 139 dbInfo, ok := infoSchema.SchemaByName(model.NewCIStr("test_db")) 140 c.Assert(ok, IsTrue, Commentf("DB info not exist")) 141 tableInfo, err := infoSchema.TableByName(model.NewCIStr("test_db"), model.NewCIStr("test_table")) 142 c.Assert(err, IsNil, Commentf("Error get table info: %s", err)) 143 tables := []*metautil.Table{{ 144 DB: dbInfo, 145 Info: tableInfo.Meta(), 146 }} 147 metaBytes, err := s.storage.ReadFile(ctx, metautil.MetaFile) 148 c.Assert(err, IsNil) 149 mockMeta := &backuppb.BackupMeta{} 150 err = proto.Unmarshal(metaBytes, mockMeta) 151 c.Assert(err, IsNil) 152 // check the schema version 153 c.Assert(mockMeta.Version, Equals, int32(metautil.MetaV1)) 154 metaReader := metautil.NewMetaReader(mockMeta, s.storage) 155 allDDLJobsBytes, err := metaReader.ReadDDLs(ctx) 156 c.Assert(err, IsNil) 157 var allDDLJobs []*model.Job 158 err = json.Unmarshal(allDDLJobsBytes, &allDDLJobs) 159 c.Assert(err, IsNil) 160 161 ddlJobs := restore.FilterDDLJobs(allDDLJobs, tables) 162 for _, job := range ddlJobs { 163 c.Logf("get ddl job: %s", job.Query) 164 } 165 c.Assert(len(ddlJobs), Equals, 7) 166 } 167 168 func (s *testRestoreSchemaSuite) TestFilterDDLJobsV2(c *C) { 169 tk := testkit.NewTestKit(c, s.mock.Storage) 170 tk.MustExec("CREATE DATABASE IF NOT EXISTS test_db;") 171 tk.MustExec("CREATE TABLE IF NOT EXISTS test_db.test_table (c1 INT);") 172 lastTS, err := s.mock.GetOracle().GetTimestamp(context.Background(), &oracle.Option{TxnScope: oracle.GlobalTxnScope}) 173 c.Assert(err, IsNil, Commentf("Error get last ts: %s", err)) 174 tk.MustExec("RENAME TABLE test_db.test_table to test_db.test_table1;") 175 tk.MustExec("DROP TABLE test_db.test_table1;") 176 tk.MustExec("DROP DATABASE test_db;") 177 tk.MustExec("CREATE DATABASE test_db;") 178 tk.MustExec("USE test_db;") 179 tk.MustExec("CREATE TABLE test_table1 (c2 CHAR(255));") 180 tk.MustExec("RENAME TABLE test_table1 to test_table;") 181 tk.MustExec("TRUNCATE TABLE test_table;") 182 183 ts, err := s.mock.GetOracle().GetTimestamp(context.Background(), &oracle.Option{TxnScope: oracle.GlobalTxnScope}) 184 c.Assert(err, IsNil, Commentf("Error get ts: %s", err)) 185 186 metaWriter := metautil.NewMetaWriter(s.storage, metautil.MetaFileSize, true) 187 ctx := context.Background() 188 metaWriter.StartWriteMetasAsync(ctx, metautil.AppendDDL) 189 err = backup.WriteBackupDDLJobs(metaWriter, s.mock.Storage, lastTS, ts) 190 c.Assert(err, IsNil, Commentf("Error get ddl jobs: %s", err)) 191 err = metaWriter.FinishWriteMetas(ctx, metautil.AppendDDL) 192 c.Assert(err, IsNil, Commentf("Flush failed", err)) 193 infoSchema, err := s.mock.Domain.GetSnapshotInfoSchema(ts) 194 c.Assert(err, IsNil, Commentf("Error get snapshot info schema: %s", err)) 195 dbInfo, ok := infoSchema.SchemaByName(model.NewCIStr("test_db")) 196 c.Assert(ok, IsTrue, Commentf("DB info not exist")) 197 tableInfo, err := infoSchema.TableByName(model.NewCIStr("test_db"), model.NewCIStr("test_table")) 198 c.Assert(err, IsNil, Commentf("Error get table info: %s", err)) 199 tables := []*metautil.Table{{ 200 DB: dbInfo, 201 Info: tableInfo.Meta(), 202 }} 203 metaBytes, err := s.storage.ReadFile(ctx, metautil.MetaFile) 204 c.Assert(err, IsNil) 205 mockMeta := &backuppb.BackupMeta{} 206 err = proto.Unmarshal(metaBytes, mockMeta) 207 c.Assert(err, IsNil) 208 // check the schema version 209 c.Assert(mockMeta.Version, Equals, int32(metautil.MetaV2)) 210 metaReader := metautil.NewMetaReader(mockMeta, s.storage) 211 allDDLJobsBytes, err := metaReader.ReadDDLs(ctx) 212 c.Assert(err, IsNil) 213 var allDDLJobs []*model.Job 214 err = json.Unmarshal(allDDLJobsBytes, &allDDLJobs) 215 c.Assert(err, IsNil) 216 217 ddlJobs := restore.FilterDDLJobs(allDDLJobs, tables) 218 for _, job := range ddlJobs { 219 c.Logf("get ddl job: %s", job.Query) 220 } 221 c.Assert(len(ddlJobs), Equals, 7) 222 }