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 }