github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/ha/stage_test.go (about)

     1  // Copyright 2020 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 ha
    15  
    16  import (
    17  	"context"
    18  	"time"
    19  
    20  	. "github.com/pingcap/check"
    21  	"github.com/pingcap/tiflow/dm/config"
    22  	"github.com/pingcap/tiflow/dm/pb"
    23  )
    24  
    25  func (t *testForEtcd) TestStageJSON(c *C) {
    26  	// stage for relay.
    27  	rs1 := NewRelayStage(pb.Stage_Running, "mysql-replica-1")
    28  	j, err := rs1.toJSON()
    29  	c.Assert(err, IsNil)
    30  	c.Assert(j, Equals, `{"expect":2,"source":"mysql-replica-1"}`)
    31  	c.Assert(j, Equals, rs1.String())
    32  
    33  	rs2, err := stageFromJSON(j)
    34  	c.Assert(err, IsNil)
    35  	c.Assert(rs2, DeepEquals, rs1)
    36  
    37  	// stage for subtask.
    38  	sts1 := NewSubTaskStage(pb.Stage_Paused, "mysql-replica-1", "task1")
    39  	j, err = sts1.toJSON()
    40  	c.Assert(err, IsNil)
    41  	c.Assert(j, Equals, `{"expect":3,"source":"mysql-replica-1","task":"task1"}`)
    42  	c.Assert(j, Equals, sts1.String())
    43  
    44  	sts2, err := stageFromJSON(j)
    45  	c.Assert(err, IsNil)
    46  	c.Assert(sts2, DeepEquals, sts1)
    47  }
    48  
    49  func (t *testForEtcd) TestRelayStageEtcd(c *C) {
    50  	defer clearTestInfoOperation(c)
    51  
    52  	var (
    53  		watchTimeout = 2 * time.Second
    54  		source1      = "mysql-replica-1"
    55  		source2      = "mysql-replica-2"
    56  		emptyStage   = Stage{}
    57  		stage1       = NewRelayStage(pb.Stage_Running, source1)
    58  		stage2       = NewRelayStage(pb.Stage_Paused, source2)
    59  	)
    60  	c.Assert(stage1.IsDeleted, IsFalse)
    61  
    62  	// no relay stage exist.
    63  	st1, rev1, err := GetRelayStage(etcdTestCli, source1)
    64  	c.Assert(err, IsNil)
    65  	c.Assert(rev1, Greater, int64(0))
    66  	c.Assert(st1, DeepEquals, emptyStage)
    67  
    68  	// put two stage.
    69  	rev2, err := PutRelayStage(etcdTestCli, stage1, stage2)
    70  	c.Assert(err, IsNil)
    71  	c.Assert(rev2, Greater, rev1)
    72  
    73  	// watch the PUT operation for stage1.
    74  	stageCh := make(chan Stage, 10)
    75  	errCh := make(chan error, 10)
    76  	ctx, cancel := context.WithTimeout(context.Background(), watchTimeout)
    77  	WatchRelayStage(ctx, etcdTestCli, source1, rev2, stageCh, errCh)
    78  	cancel()
    79  	close(stageCh)
    80  	close(errCh)
    81  	c.Assert(len(stageCh), Equals, 1)
    82  	stage1.Revision = rev2
    83  	c.Assert(<-stageCh, DeepEquals, stage1)
    84  	c.Assert(len(errCh), Equals, 0)
    85  
    86  	// get stage1 back.
    87  	st2, rev3, err := GetRelayStage(etcdTestCli, source1)
    88  	c.Assert(err, IsNil)
    89  	c.Assert(rev3, Equals, rev2)
    90  	c.Assert(st2, DeepEquals, stage1)
    91  
    92  	// get two stages.
    93  	stm, rev3, err := GetAllRelayStage(etcdTestCli)
    94  	c.Assert(err, IsNil)
    95  	c.Assert(rev3, Equals, rev2)
    96  	c.Assert(stm, HasLen, 2)
    97  	stage2.Revision = rev2
    98  	c.Assert(stm[source1], DeepEquals, stage1)
    99  	c.Assert(stm[source2], DeepEquals, stage2)
   100  
   101  	// delete stage1.
   102  	deleteOp := deleteRelayStageOp(source1)
   103  	resp, err := etcdTestCli.Txn(context.Background()).Then(deleteOp).Commit()
   104  	c.Assert(err, IsNil)
   105  	rev4 := resp.Header.Revision
   106  	c.Assert(rev4, Greater, rev3)
   107  
   108  	// watch the DELETE operation for stage1.
   109  	stageCh = make(chan Stage, 10)
   110  	errCh = make(chan error, 10)
   111  	ctx, cancel = context.WithTimeout(context.Background(), watchTimeout)
   112  	WatchRelayStage(ctx, etcdTestCli, source1, rev4, stageCh, errCh)
   113  	cancel()
   114  	close(stageCh)
   115  	close(errCh)
   116  	c.Assert(len(stageCh), Equals, 1)
   117  	st3 := <-stageCh
   118  	c.Assert(st3.IsDeleted, IsTrue)
   119  	c.Assert(len(errCh), Equals, 0)
   120  
   121  	// get again, not exists now.
   122  	st4, rev5, err := GetRelayStage(etcdTestCli, source1)
   123  	c.Assert(err, IsNil)
   124  	c.Assert(rev5, Equals, rev4)
   125  	c.Assert(st4, DeepEquals, emptyStage)
   126  }
   127  
   128  func (t *testForEtcd) TestSubTaskStageEtcd(c *C) {
   129  	defer clearTestInfoOperation(c)
   130  
   131  	var (
   132  		watchTimeout = 2 * time.Second
   133  		source       = "mysql-replica-1"
   134  		task1        = "task-1"
   135  		task2        = "task-2"
   136  		stage1       = NewSubTaskStage(pb.Stage_Running, source, task1)
   137  		stage2       = NewSubTaskStage(pb.Stage_Paused, source, task2)
   138  	)
   139  
   140  	// no stage exists.
   141  	st1, rev1, err := GetSubTaskStage(etcdTestCli, source, task1)
   142  	c.Assert(err, IsNil)
   143  	c.Assert(rev1, Greater, int64(0))
   144  	c.Assert(st1, HasLen, 0)
   145  
   146  	// put two stages.
   147  	rev2, err := PutSubTaskStage(etcdTestCli, stage1, stage2)
   148  	c.Assert(err, IsNil)
   149  	c.Assert(rev2, Greater, rev1)
   150  
   151  	// watch the PUT operation for stages.
   152  	stageCh := make(chan Stage, 10)
   153  	errCh := make(chan error, 10)
   154  	ctx, cancel := context.WithTimeout(context.Background(), watchTimeout)
   155  	WatchSubTaskStage(ctx, etcdTestCli, source, rev2, stageCh, errCh)
   156  	cancel()
   157  	close(stageCh)
   158  	close(errCh)
   159  	c.Assert(len(stageCh), Equals, 2)
   160  	stage1.Revision = rev2
   161  	stage2.Revision = rev2
   162  	c.Assert(<-stageCh, DeepEquals, stage1)
   163  	c.Assert(<-stageCh, DeepEquals, stage2)
   164  	c.Assert(len(errCh), Equals, 0)
   165  
   166  	// get stages back without specified task.
   167  	stm, rev3, err := GetSubTaskStage(etcdTestCli, source, "")
   168  	c.Assert(err, IsNil)
   169  	c.Assert(rev3, Equals, rev2)
   170  	c.Assert(stm, HasLen, 2)
   171  	c.Assert(stm[task1], DeepEquals, stage1)
   172  	c.Assert(stm[task2], DeepEquals, stage2)
   173  
   174  	// get the stage back with specified task.
   175  	stm, rev3, err = GetSubTaskStage(etcdTestCli, source, task1)
   176  	c.Assert(err, IsNil)
   177  	c.Assert(rev3, Equals, rev2)
   178  	c.Assert(stm, HasLen, 1)
   179  	c.Assert(stm[task1], DeepEquals, stage1)
   180  
   181  	// get all stages.
   182  	stmm, rev3, err := GetAllSubTaskStage(etcdTestCli)
   183  	c.Assert(err, IsNil)
   184  	c.Assert(rev3, Equals, rev2)
   185  	c.Assert(stmm, HasLen, 1)
   186  	c.Assert(stmm[source], HasLen, 2)
   187  	c.Assert(stmm[source][task1], DeepEquals, stage1)
   188  	c.Assert(stmm[source][task2], DeepEquals, stage2)
   189  
   190  	// delete two stages.
   191  	rev4, err := DeleteSubTaskStage(etcdTestCli, stage1, stage2)
   192  	c.Assert(err, IsNil)
   193  	c.Assert(rev4, Greater, rev3)
   194  
   195  	// watch the DELETE operation for stages.
   196  	stageCh = make(chan Stage, 10)
   197  	errCh = make(chan error, 10)
   198  	ctx, cancel = context.WithTimeout(context.Background(), watchTimeout)
   199  	WatchSubTaskStage(ctx, etcdTestCli, source, rev4, stageCh, errCh)
   200  	cancel()
   201  	close(stageCh)
   202  	close(errCh)
   203  	c.Assert(len(stageCh), Equals, 2)
   204  	for st2 := range stageCh {
   205  		c.Assert(st2.IsDeleted, IsTrue)
   206  	}
   207  	c.Assert(len(errCh), Equals, 0)
   208  
   209  	// get again, not exists now.
   210  	stm, rev5, err := GetSubTaskStage(etcdTestCli, source, task1)
   211  	c.Assert(err, IsNil)
   212  	c.Assert(rev5, Equals, rev4)
   213  	c.Assert(stm, HasLen, 0)
   214  }
   215  
   216  func (t *testForEtcd) TestGetSubTaskStageConfigEtcd(c *C) {
   217  	defer clearTestInfoOperation(c)
   218  
   219  	cfg := config.SubTaskConfig{}
   220  	c.Assert(cfg.Decode(config.SampleSubtaskConfig, true), IsNil)
   221  	source := cfg.SourceID
   222  	task := cfg.Name
   223  	stage := NewSubTaskStage(pb.Stage_Running, source, task)
   224  
   225  	// no subtask stage and config
   226  	stm, validatorM, scm, rev1, err := GetSubTaskStageConfig(etcdTestCli, source)
   227  	c.Assert(err, IsNil)
   228  	c.Assert(rev1, Greater, int64(0))
   229  	c.Assert(stm, HasLen, 0)
   230  	c.Assert(validatorM, HasLen, 0)
   231  	c.Assert(scm, HasLen, 0)
   232  
   233  	// put subtask config and stage at the same time
   234  	rev2, err := PutSubTaskCfgStage(etcdTestCli, []config.SubTaskConfig{cfg}, []Stage{stage}, []Stage{stage})
   235  	c.Assert(err, IsNil)
   236  	c.Assert(rev2, Greater, rev1)
   237  
   238  	// get subtask config and stage at the same time
   239  	stm, validatorM, scm, rev3, err := GetSubTaskStageConfig(etcdTestCli, source)
   240  	c.Assert(err, IsNil)
   241  	c.Assert(rev3, Equals, rev2)
   242  	c.Assert(stm, HasLen, 1)
   243  	c.Assert(validatorM, HasLen, 1)
   244  	stage.Revision = rev2
   245  	c.Assert(stm[task], DeepEquals, stage)
   246  	c.Assert(validatorM[task], DeepEquals, stage)
   247  	c.Assert(scm[task], DeepEquals, cfg)
   248  }