github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/ha/bound_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 ) 23 24 func (t *testForEtcd) TestSourceBoundJSON(c *C) { 25 b1 := NewSourceBound("mysql-replica-1", "dm-worker-1") 26 27 j, err := b1.toJSON() 28 c.Assert(err, IsNil) 29 c.Assert(j, Equals, `{"source":"mysql-replica-1","worker":"dm-worker-1"}`) 30 c.Assert(j, Equals, b1.String()) 31 32 b2, err := sourceBoundFromJSON(j) 33 c.Assert(err, IsNil) 34 c.Assert(b2, DeepEquals, b1) 35 } 36 37 func (t *testForEtcd) TestSourceBoundEtcd(c *C) { 38 defer clearTestInfoOperation(c) 39 40 var ( 41 watchTimeout = 2 * time.Second 42 worker1 = "dm-worker-1" 43 worker2 = "dm-worker-2" 44 bound1 = NewSourceBound("mysql-replica-1", worker1) 45 bound2 = NewSourceBound("mysql-replica-2", worker2) 46 ) 47 c.Assert(bound1.IsDeleted, IsFalse) 48 49 // no bound exists. 50 sbm1, rev1, err := GetSourceBound(etcdTestCli, "") 51 c.Assert(err, IsNil) 52 c.Assert(rev1, Greater, int64(0)) 53 c.Assert(sbm1, HasLen, 0) 54 55 // put two bounds. 56 rev2, err := PutSourceBound(etcdTestCli, bound1) 57 c.Assert(err, IsNil) 58 c.Assert(rev2, Greater, rev1) 59 rev3, err := PutSourceBound(etcdTestCli, bound2) 60 c.Assert(err, IsNil) 61 c.Assert(rev3, Greater, rev2) 62 63 // watch the PUT operation for the bound1. 64 boundCh := make(chan SourceBound, 10) 65 errCh := make(chan error, 10) 66 ctx, cancel := context.WithTimeout(context.Background(), watchTimeout) 67 WatchSourceBound(ctx, etcdTestCli, worker1, rev2, boundCh, errCh) 68 cancel() 69 close(boundCh) 70 close(errCh) 71 c.Assert(len(boundCh), Equals, 1) 72 bound1.Revision = rev2 73 c.Assert(<-boundCh, DeepEquals, bound1) 74 c.Assert(len(errCh), Equals, 0) 75 76 // get bound1 back. 77 sbm2, rev4, err := GetSourceBound(etcdTestCli, worker1) 78 c.Assert(err, IsNil) 79 c.Assert(rev4, Equals, rev3) 80 c.Assert(sbm2, HasLen, 1) 81 c.Assert(sbm2[worker1], DeepEquals, bound1) 82 83 // get bound1 and bound2 back. 84 sbm2, rev4, err = GetSourceBound(etcdTestCli, "") 85 c.Assert(err, IsNil) 86 c.Assert(rev4, Equals, rev3) 87 c.Assert(sbm2, HasLen, 2) 88 c.Assert(sbm2[worker1], DeepEquals, bound1) 89 bound2.Revision = rev3 90 c.Assert(sbm2[worker2], DeepEquals, bound2) 91 92 // delete bound1. 93 rev5, err := DeleteSourceBound(etcdTestCli, worker1) 94 c.Assert(err, IsNil) 95 c.Assert(rev5, Greater, rev4) 96 97 // delete bound2. 98 rev6, err := DeleteSourceBound(etcdTestCli, worker2) 99 c.Assert(err, IsNil) 100 c.Assert(rev6, Greater, rev5) 101 102 // watch the DELETE operation for bound1. 103 boundCh = make(chan SourceBound, 10) 104 errCh = make(chan error, 10) 105 ctx, cancel = context.WithTimeout(context.Background(), watchTimeout) 106 WatchSourceBound(ctx, etcdTestCli, worker1, rev5, boundCh, errCh) 107 cancel() 108 close(boundCh) 109 close(errCh) 110 c.Assert(len(boundCh), Equals, 1) 111 bo := <-boundCh 112 c.Assert(bo.IsDeleted, IsTrue) 113 c.Assert(bo.Revision, Equals, rev5) 114 c.Assert(len(errCh), Equals, 0) 115 116 // get again, bound1 not exists now. 117 sbm3, rev7, err := GetSourceBound(etcdTestCli, worker1) 118 c.Assert(err, IsNil) 119 c.Assert(rev7, Equals, rev6) 120 c.Assert(sbm3, HasLen, 0) 121 } 122 123 func (t *testForEtcd) TestGetSourceBoundConfigEtcd(c *C) { 124 defer clearTestInfoOperation(c) 125 126 var ( 127 worker = "dm-worker-1" 128 source = "mysql-replica-1" 129 bound = NewSourceBound(source, worker) 130 ) 131 cfg, err := config.LoadFromFile(sourceSampleFilePath) 132 c.Assert(err, IsNil) 133 cfg.SourceID = source 134 // no source bound and config 135 bound1, cfg1, rev1, err := GetSourceBoundConfig(etcdTestCli, worker) 136 c.Assert(err, IsNil) 137 c.Assert(rev1, Greater, int64(0)) 138 c.Assert(bound1.IsEmpty(), IsTrue) 139 c.Assert(cfg1, IsNil) 140 141 rev2, err := PutSourceBound(etcdTestCli, bound) 142 c.Assert(err, IsNil) 143 c.Assert(rev2, Greater, rev1) 144 // get source bound and config, but config is empty 145 // nolint:dogsled 146 _, _, _, err = GetSourceBoundConfig(etcdTestCli, worker) 147 c.Assert(err, ErrorMatches, ".*doesn't have related source config in etcd.*") 148 149 rev3, err := PutSourceCfg(etcdTestCli, cfg) 150 c.Assert(err, IsNil) 151 c.Assert(rev3, Greater, rev2) 152 // get source bound and config 153 bound2, cfg2, rev4, err := GetSourceBoundConfig(etcdTestCli, worker) 154 c.Assert(err, IsNil) 155 c.Assert(rev4, Equals, rev3) 156 bound.Revision = rev2 157 c.Assert(bound2, DeepEquals, bound) 158 c.Assert(cfg2, DeepEquals, cfg) 159 }