github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/shardddl/optimism/table_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 "testing" 19 "time" 20 21 . "github.com/pingcap/check" 22 "github.com/stretchr/testify/require" 23 ) 24 25 func (t *testForEtcd) TestSourceTablesJSON(c *C) { 26 st1 := NewSourceTables("test", "mysql-replica-1") 27 st1.AddTable("db1", "tbl1", "db", "tbl") 28 j, err := st1.toJSON() 29 c.Assert(err, IsNil) 30 c.Assert(j, Equals, `{"task":"test","source":"mysql-replica-1","tables":{"db":{"tbl":{"db1":{"tbl1":{}}}}}}`) 31 c.Assert(j, Equals, st1.String()) 32 33 st2, err := sourceTablesFromJSON(j) 34 c.Assert(err, IsNil) 35 c.Assert(st2, DeepEquals, st1) 36 } 37 38 func (t *testForEtcd) TestSourceTablesAddRemove(c *C) { 39 var ( 40 task = "task" 41 source = "mysql-replica-1" 42 downSchema = "foo" 43 downTable1 = "bar1" 44 downTable2 = "bar2" 45 st = NewSourceTables(task, source) 46 ) 47 48 // no target table exist. 49 c.Assert(st.TargetTable(downSchema, downTable1).IsEmpty(), IsTrue) 50 c.Assert(st.TargetTable(downSchema, downTable2).IsEmpty(), IsTrue) 51 52 // add a table for downTable1. 53 c.Assert(st.AddTable("foo1", "bar1", downSchema, downTable1), IsTrue) 54 c.Assert(st.AddTable("foo1", "bar1", downSchema, downTable1), IsFalse) 55 c.Assert(st.TargetTable(downSchema, downTable1), DeepEquals, 56 newTargetTable(task, source, downSchema, downTable1, map[string]map[string]struct{}{ 57 "foo1": {"bar1": struct{}{}}, 58 })) 59 c.Assert(st.TargetTable(downSchema, downTable2).IsEmpty(), IsTrue) 60 61 // add a table for downTable2. 62 c.Assert(st.AddTable("foo2", "bar2", downSchema, downTable2), IsTrue) 63 c.Assert(st.AddTable("foo2", "bar2", downSchema, downTable2), IsFalse) 64 c.Assert(st.TargetTable(downSchema, downTable2), DeepEquals, 65 newTargetTable(task, source, downSchema, downTable2, map[string]map[string]struct{}{ 66 "foo2": {"bar2": struct{}{}}, 67 })) 68 69 // remove a table for downTable1. 70 c.Assert(st.RemoveTable("foo1", "bar1", downSchema, downTable1), IsTrue) 71 c.Assert(st.RemoveTable("foo1", "bar1", downSchema, downTable1), IsFalse) 72 c.Assert(st.TargetTable(downSchema, downTable1).IsEmpty(), IsTrue) 73 74 // remove a table for downTable2. 75 c.Assert(st.RemoveTable("foo2", "bar2", downSchema, downTable2), IsTrue) 76 c.Assert(st.RemoveTable("foo2", "bar2", downSchema, downTable2), IsFalse) 77 c.Assert(st.TargetTable(downSchema, downTable2).IsEmpty(), IsTrue) 78 } 79 80 func (t *testForEtcd) TestSourceTablesEtcd(c *C) { 81 defer clearTestInfoOperation(c) 82 83 var ( 84 watchTimeout = 2 * time.Second 85 task = "task" 86 source1 = "mysql-replica-1" 87 source2 = "mysql-replica-2" 88 downSchema = "db" 89 downTable = "tbl" 90 st1 = NewSourceTables(task, source1) 91 st2 = NewSourceTables(task, source2) 92 ) 93 94 st1.AddTable("db", "tbl-1", downSchema, downTable) 95 st1.AddTable("db", "tbl-2", downSchema, downTable) 96 st2.AddTable("db", "tbl-1", downSchema, downTable) 97 st2.AddTable("db", "tbl-2", downSchema, downTable) 98 99 // put two SourceTables. 100 rev1, err := PutSourceTables(etcdTestCli, st1) 101 c.Assert(err, IsNil) 102 rev2, err := PutSourceTables(etcdTestCli, st2) 103 c.Assert(err, IsNil) 104 c.Assert(rev2, Greater, rev1) 105 106 // get with two SourceTables. 107 stm, rev3, err := GetAllSourceTables(etcdTestCli) 108 c.Assert(err, IsNil) 109 c.Assert(rev3, Equals, rev2) 110 c.Assert(stm, HasLen, 1) 111 c.Assert(stm[task], HasLen, 2) 112 c.Assert(stm[task][source1], DeepEquals, st1) 113 c.Assert(stm[task][source2], DeepEquals, st2) 114 115 // watch with an older revision for all SourceTables. 116 wch := make(chan SourceTables, 10) 117 ech := make(chan error, 10) 118 ctx, cancel := context.WithTimeout(context.Background(), watchTimeout) 119 WatchSourceTables(ctx, etcdTestCli, rev1, wch, ech) 120 cancel() 121 close(wch) 122 close(ech) 123 124 // get two source tables. 125 c.Assert(len(wch), Equals, 2) 126 c.Assert(<-wch, DeepEquals, st1) 127 c.Assert(<-wch, DeepEquals, st2) 128 c.Assert(len(ech), Equals, 0) 129 130 // delete tow sources tables. 131 _, err = DeleteSourceTables(etcdTestCli, st1) 132 c.Assert(err, IsNil) 133 rev4, err := DeleteSourceTables(etcdTestCli, st2) 134 c.Assert(err, IsNil) 135 136 // get without SourceTables. 137 stm, rev5, err := GetAllSourceTables(etcdTestCli) 138 c.Assert(err, IsNil) 139 c.Assert(rev5, Equals, rev4) 140 c.Assert(stm, HasLen, 0) 141 142 // watch the deletion for SourceTables. 143 wch = make(chan SourceTables, 10) 144 ech = make(chan error, 10) 145 ctx, cancel = context.WithTimeout(context.Background(), watchTimeout) 146 WatchSourceTables(ctx, etcdTestCli, rev4, wch, ech) 147 cancel() 148 close(wch) 149 close(ech) 150 c.Assert(len(wch), Equals, 1) 151 std := <-wch 152 c.Assert(std.IsDeleted, IsTrue) 153 c.Assert(std.Task, Equals, st2.Task) 154 c.Assert(std.Source, Equals, st2.Source) 155 c.Assert(len(ech), Equals, 0) 156 } 157 158 func TestToRouteTable(t *testing.T) { 159 var ( 160 task1 = "task-1" 161 source1 = "mysql-replica-1" 162 downSchema = "db" 163 downTable = "tbl" 164 upSchema = "db" 165 upTable1 = "tbl-1" 166 upTable2 = "tbl-2" 167 168 tt11 = newTargetTable(task1, source1, downSchema, downTable, map[string]map[string]struct{}{ 169 upSchema: {upTable1: struct{}{}, upTable2: struct{}{}}, 170 }) 171 172 result = map[RouteTable]struct{}{ 173 { 174 UpSchema: upSchema, 175 UpTable: upTable1, 176 DownSchema: downSchema, 177 DownTable: downTable, 178 }: {}, 179 { 180 UpSchema: upSchema, 181 UpTable: upTable2, 182 DownSchema: downSchema, 183 DownTable: downTable, 184 }: {}, 185 } 186 187 st11 = NewSourceTables(task1, source1) 188 ) 189 190 rt := st11.toRouteTable() 191 require.Len(t, rt, 0) 192 193 for schema, tables := range tt11.UpTables { 194 for table := range tables { 195 st11.AddTable(schema, table, tt11.DownSchema, tt11.DownTable) 196 } 197 } 198 199 rt = st11.toRouteTable() 200 require.Len(t, rt, 2) 201 require.Equal(t, result, rt) 202 } 203 204 func TestDiffSourceTable(t *testing.T) { 205 var ( 206 task1 = "task-1" 207 source1 = "mysql-replica-1" 208 downSchema = "db" 209 downTable = "tbl" 210 upSchema = "db" 211 upTable1 = "tbl-1" 212 upTable2 = "tbl-2" 213 214 tt11 = newTargetTable(task1, source1, downSchema, downTable, map[string]map[string]struct{}{ 215 upSchema: {upTable1: struct{}{}, upTable2: struct{}{}}, 216 }) 217 218 result1 = map[RouteTable]struct{}{ 219 { 220 UpSchema: upSchema, 221 UpTable: upTable1, 222 DownSchema: downSchema, 223 DownTable: downTable, 224 }: {}, 225 } 226 result2 = map[RouteTable]struct{}{ 227 { 228 UpSchema: upSchema, 229 UpTable: upTable2, 230 DownSchema: downSchema, 231 DownTable: downTable, 232 }: {}, 233 } 234 st11 SourceTables 235 st12 SourceTables 236 ) 237 238 addTables, dropTables := DiffSourceTables(st11, st12) 239 require.Len(t, addTables, 0) 240 require.Len(t, dropTables, 0) 241 242 st11 = NewSourceTables(task1, source1) 243 st12 = NewSourceTables(task1, source1) 244 addTables, dropTables = DiffSourceTables(st11, st12) 245 require.Len(t, addTables, 0) 246 require.Len(t, dropTables, 0) 247 248 st11.AddTable(upSchema, upTable1, tt11.DownSchema, tt11.DownTable) 249 250 addTables, dropTables = DiffSourceTables(st11, st12) 251 require.Len(t, addTables, 0) 252 require.Len(t, dropTables, 1) 253 require.Equal(t, dropTables, result1) 254 addTables, dropTables = DiffSourceTables(st12, st11) 255 require.Len(t, addTables, 1) 256 require.Len(t, dropTables, 0) 257 require.Equal(t, addTables, result1) 258 259 st12.AddTable(upSchema, upTable2, tt11.DownSchema, tt11.DownTable) 260 addTables, dropTables = DiffSourceTables(st11, st12) 261 require.Len(t, addTables, 1) 262 require.Len(t, dropTables, 1) 263 require.Equal(t, addTables, result2) 264 require.Equal(t, dropTables, result1) 265 }