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  }