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  }