github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/shardddl/optimism/operation_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 optimism 15 16 import ( 17 "context" 18 "time" 19 20 . "github.com/pingcap/check" 21 ) 22 23 func (t *testForEtcd) TestOperationJSON(c *C) { 24 o1 := NewOperation("test-ID", "test", "mysql-replica-1", "db-1", "tbl-1", []string{ 25 "ALTER TABLE tbl ADD COLUMN c1 INT", 26 }, ConflictDetected, "conflict", true, []string{}) 27 28 j, err := o1.toJSON() 29 c.Assert(err, IsNil) 30 c.Assert(j, Equals, `{"id":"test-ID","task":"test","source":"mysql-replica-1","up-schema":"db-1","up-table":"tbl-1","ddls":["ALTER TABLE tbl ADD COLUMN c1 INT"],"conflict-stage":"detected","conflict-message":"conflict","done":true,"cols":[]}`) 31 c.Assert(j, Equals, o1.String()) 32 33 o2, err := operationFromJSON(j) 34 c.Assert(err, IsNil) 35 c.Assert(o2, DeepEquals, o1) 36 } 37 38 func (t *testForEtcd) TestOperationEtcd(c *C) { 39 defer clearTestInfoOperation(c) 40 41 var ( 42 watchTimeout = 2 * time.Second 43 task1 = "test1" 44 task2 = "test2" 45 upSchema = "foo_1" 46 upTable = "bar_1" 47 ID1 = "test1-`foo`.`bar`" 48 ID2 = "test2-`foo`.`bar`" 49 source1 = "mysql-replica-1" 50 DDLs = []string{"ALTER TABLE bar ADD COLUMN c1 INT"} 51 op11 = NewOperation(ID1, task1, source1, upSchema, upTable, DDLs, ConflictNone, "", false, []string{}) 52 op21 = NewOperation(ID2, task2, source1, upSchema, upTable, DDLs, ConflictResolved, "", true, []string{}) 53 ) 54 55 // put the same keys twice. 56 rev1, succ, err := PutOperation(etcdTestCli, false, op11, 0) 57 c.Assert(err, IsNil) 58 c.Assert(succ, IsTrue) 59 rev2, succ, err := PutOperation(etcdTestCli, false, op11, 0) 60 c.Assert(err, IsNil) 61 c.Assert(succ, IsTrue) 62 c.Assert(rev2, Greater, rev1) 63 64 // start the watcher with the same revision as the last PUT for the specified task and source. 65 wch := make(chan Operation, 10) 66 ech := make(chan error, 10) 67 ctx, cancel := context.WithTimeout(context.Background(), watchTimeout) 68 WatchOperationPut(ctx, etcdTestCli, task1, source1, upSchema, upTable, rev2, wch, ech) 69 cancel() 70 close(wch) 71 close(ech) 72 73 // watch should only get op11. 74 c.Assert(len(ech), Equals, 0) 75 c.Assert(len(wch), Equals, 1) 76 op11.Revision = rev2 77 c.Assert(<-wch, DeepEquals, op11) 78 79 // put for another task. 80 rev3, succ, err := PutOperation(etcdTestCli, false, op21, 0) 81 c.Assert(err, IsNil) 82 c.Assert(succ, IsTrue) 83 84 // start the watch with an older revision for all tasks and sources. 85 wch = make(chan Operation, 10) 86 ech = make(chan error, 10) 87 ctx, cancel = context.WithTimeout(context.Background(), watchTimeout) 88 WatchOperationPut(ctx, etcdTestCli, "", "", "", "", rev2, wch, ech) 89 cancel() 90 close(wch) 91 close(ech) 92 93 // watch should get 2 operations. 94 c.Assert(len(ech), Equals, 0) 95 c.Assert(len(wch), Equals, 2) 96 c.Assert(<-wch, DeepEquals, op11) 97 op21.Revision = rev3 98 c.Assert(<-wch, DeepEquals, op21) 99 100 // get all operations. 101 opm, rev4, err := GetAllOperations(etcdTestCli) 102 c.Assert(err, IsNil) 103 c.Assert(rev4, Equals, rev3) 104 c.Assert(opm, HasLen, 2) 105 c.Assert(opm, HasKey, task1) 106 c.Assert(opm, HasKey, task2) 107 c.Assert(opm[task1], HasLen, 1) 108 op11.Revision = rev2 109 c.Assert(opm[task1][source1][upSchema][upTable], DeepEquals, op11) 110 c.Assert(opm[task2], HasLen, 1) 111 op21.Revision = rev3 112 c.Assert(opm[task2][source1][upSchema][upTable], DeepEquals, op21) 113 114 // put for `skipDone` with `done` in etcd, the operations should not be skipped. 115 // case: kv's "the `done` field is not `true`". 116 rev5, succ, err := PutOperation(etcdTestCli, true, op11, 0) 117 c.Assert(err, IsNil) 118 c.Assert(succ, IsTrue) 119 c.Assert(rev5, Greater, rev4) 120 121 // delete op11. 122 deleteOp := deleteOperationOp(op11) 123 _, err = etcdTestCli.Txn(context.Background()).Then(deleteOp).Commit() 124 c.Assert(err, IsNil) 125 126 // get again, op11 should be deleted. 127 opm, _, err = GetAllOperations(etcdTestCli) 128 c.Assert(err, IsNil) 129 c.Assert(opm[task1], HasLen, 0) 130 131 // put for `skipDone` with `done` in etcd, the operations should not be skipped. 132 // case: kv "not exist". 133 rev6, succ, err := PutOperation(etcdTestCli, true, op11, 0) 134 c.Assert(err, IsNil) 135 c.Assert(succ, IsTrue) 136 137 // get again, op11 should be putted. 138 opm, _, err = GetAllOperations(etcdTestCli) 139 c.Assert(err, IsNil) 140 c.Assert(opm[task1], HasLen, 1) 141 op11.Revision = rev6 142 c.Assert(opm[task1][source1][upSchema][upTable], DeepEquals, op11) 143 144 // update op11 to `done`. 145 op11c := op11 146 op11c.Done = true 147 rev7, succ, err := PutOperation(etcdTestCli, true, op11c, 0) 148 c.Assert(err, IsNil) 149 c.Assert(succ, IsTrue) 150 c.Assert(rev7, Greater, rev6) 151 152 // put for `skipDone` with `done` in etcd, the operations should not be skipped. 153 // case: operation modRevision < info's modRevision 154 rev8, succ, err := PutOperation(etcdTestCli, true, op11c, rev7+10) 155 c.Assert(err, IsNil) 156 c.Assert(succ, IsTrue) 157 c.Assert(rev8, Greater, rev7) 158 159 // put for `skipDone` with `done` in etcd, the operations should be skipped. 160 // case: kv's ("exist" and "the `done` field is `true`"). 161 rev9, succ, err := PutOperation(etcdTestCli, true, op11, rev6) 162 c.Assert(err, IsNil) 163 c.Assert(succ, IsFalse) 164 c.Assert(rev9, Equals, rev8) 165 }