github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/changefeed_test.go (about) 1 // Copyright 2021 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package cdc 15 16 import ( 17 "context" 18 "net/url" 19 "time" 20 21 "github.com/pingcap/check" 22 timodel "github.com/pingcap/parser/model" 23 "github.com/pingcap/ticdc/cdc/kv" 24 "github.com/pingcap/ticdc/cdc/model" 25 "github.com/pingcap/ticdc/pkg/etcd" 26 "github.com/pingcap/ticdc/pkg/util" 27 "github.com/pingcap/ticdc/pkg/util/testleak" 28 "go.etcd.io/etcd/clientv3" 29 "go.etcd.io/etcd/clientv3/concurrency" 30 "go.etcd.io/etcd/embed" 31 "golang.org/x/sync/errgroup" 32 ) 33 34 type changefeedSuite struct { 35 e *embed.Etcd 36 clientURL *url.URL 37 client kv.CDCEtcdClient 38 sess *concurrency.Session 39 ctx context.Context 40 cancel context.CancelFunc 41 errg *errgroup.Group 42 } 43 44 var _ = check.Suite(&changefeedSuite{}) 45 46 func (s *changefeedSuite) SetUpTest(c *check.C) { 47 dir := c.MkDir() 48 var err error 49 s.clientURL, s.e, err = etcd.SetupEmbedEtcd(dir) 50 c.Assert(err, check.IsNil) 51 client, err := clientv3.New(clientv3.Config{ 52 Endpoints: []string{s.clientURL.String()}, 53 DialTimeout: 3 * time.Second, 54 }) 55 c.Assert(err, check.IsNil) 56 sess, err := concurrency.NewSession(client) 57 c.Assert(err, check.IsNil) 58 s.sess = sess 59 s.client = kv.NewCDCEtcdClient(context.Background(), client) 60 s.ctx, s.cancel = context.WithCancel(context.Background()) 61 s.errg = util.HandleErrWithErrGroup(s.ctx, s.e.Err(), func(e error) { c.Log(e) }) 62 } 63 64 func (s *changefeedSuite) TearDownTest(c *check.C) { 65 s.e.Close() 66 s.cancel() 67 err := s.errg.Wait() 68 if err != nil { 69 c.Errorf("Error group error: %s", err) 70 } 71 s.client.Close() //nolint:errcheck 72 } 73 74 func (s *changefeedSuite) TestHandleMoveTableJobs(c *check.C) { 75 defer testleak.AfterTest(c)() 76 defer s.TearDownTest(c) 77 changefeed := new(changeFeed) 78 captureID1 := "capture1" 79 captureID2 := "capture2" 80 changefeed.id = "changefeed-test" 81 changefeed.leaseID = s.sess.Lease() 82 changefeed.etcdCli = s.client 83 changefeed.status = new(model.ChangeFeedStatus) 84 changefeed.orphanTables = map[model.TableID]model.Ts{} 85 captures := make(map[model.CaptureID]*model.CaptureInfo) 86 captures[captureID1] = &model.CaptureInfo{ 87 ID: captureID1, 88 } 89 captures[captureID2] = &model.CaptureInfo{ 90 ID: captureID2, 91 } 92 changefeed.taskStatus = make(map[model.CaptureID]*model.TaskStatus) 93 changefeed.taskStatus[captureID1] = &model.TaskStatus{Tables: map[model.TableID]*model.TableReplicaInfo{1: {}}} 94 changefeed.taskStatus[captureID2] = &model.TaskStatus{Tables: map[model.TableID]*model.TableReplicaInfo{}} 95 changefeed.moveTableJobs = make(map[model.TableID]*model.MoveTableJob) 96 changefeed.moveTableJobs[1] = &model.MoveTableJob{ 97 TableID: 1, 98 From: captureID1, 99 To: captureID2, 100 TableReplicaInfo: new(model.TableReplicaInfo), 101 } 102 err := changefeed.handleMoveTableJobs(s.ctx, captures) 103 c.Assert(err, check.IsNil) 104 taskStatuses, err := s.client.GetAllTaskStatus(s.ctx, changefeed.id) 105 c.Assert(err, check.IsNil) 106 taskStatuses[captureID1].ModRevision = 0 107 c.Assert(taskStatuses, check.DeepEquals, model.ProcessorsInfos{captureID1: { 108 Tables: map[model.TableID]*model.TableReplicaInfo{}, 109 Operation: map[model.TableID]*model.TableOperation{1: { 110 Delete: true, 111 Flag: model.OperFlagMoveTable, 112 }}, 113 }}) 114 115 // finish operation 116 err = s.client.PutTaskStatus(s.ctx, changefeed.id, captureID1, &model.TaskStatus{ 117 Tables: map[model.TableID]*model.TableReplicaInfo{}, 118 Operation: map[model.TableID]*model.TableOperation{}, 119 }) 120 c.Assert(err, check.IsNil) 121 delete(changefeed.taskStatus[captureID1].Operation, 1) 122 123 // capture2 offline 124 delete(captures, captureID2) 125 delete(changefeed.taskStatus, captureID2) 126 127 err = changefeed.handleMoveTableJobs(s.ctx, captures) 128 c.Assert(err, check.IsNil) 129 c.Assert(changefeed.orphanTables, check.HasKey, model.TableID(1)) 130 c.Assert(changefeed.moveTableJobs, check.HasLen, 0) 131 } 132 133 func (s *changefeedSuite) TestUpdatePartition(c *check.C) { 134 defer testleak.AfterTest(c)() 135 defer s.TearDownTest(c) 136 137 cf := changeFeed{ 138 partitions: map[model.TableID][]int64{ 139 51: {53, 55, 57}, 140 }, 141 orphanTables: make(map[model.TableID]model.Ts), 142 toCleanTables: make(map[model.TableID]model.Ts), 143 } 144 tblInfo := &timodel.TableInfo{ 145 ID: 51, 146 Partition: &timodel.PartitionInfo{ 147 Enable: true, 148 Definitions: []timodel.PartitionDefinition{ 149 {ID: 57}, {ID: 59}, {ID: 61}, 150 }, 151 }, 152 } 153 startTs := uint64(100) 154 155 cf.updatePartition(tblInfo, startTs) 156 c.Assert(cf.orphanTables, check.DeepEquals, map[model.TableID]model.Ts{ 157 59: startTs, 158 61: startTs, 159 }) 160 c.Assert(cf.toCleanTables, check.DeepEquals, map[model.TableID]model.Ts{ 161 53: startTs, 162 55: startTs, 163 }) 164 c.Assert(cf.partitions, check.DeepEquals, map[model.TableID][]int64{ 165 51: {57, 59, 61}, 166 }) 167 }