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  }