github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/binlog-filter/filter_test.go (about) 1 // Copyright 2018 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 filter 15 16 import ( 17 "testing" 18 19 "github.com/pingcap/errors" 20 selector "github.com/pingcap/tidb/pkg/util/table-rule-selector" 21 "github.com/stretchr/testify/require" 22 ) 23 24 func TestFilter(t *testing.T) { 25 rules := []*BinlogEventRule{ 26 {"Test_1_*", "abc*", []EventType{DeleteEvent, InsertEvent, CreateIndex, DropIndex, DropView}, []string{"^DROP\\s+PROCEDURE", "^CREATE\\s+PROCEDURE"}, nil, Ignore}, 27 {"xxx_*", "abc_*", []EventType{AllDML, NoneDDL}, nil, nil, Ignore}, 28 {"yyy_*", "abc_*", []EventType{EventType("ALL DML")}, nil, nil, Do}, 29 {"Test_1_*", "abc*", []EventType{"wrong event"}, []string{"^DROP\\s+PROCEDURE", "^CREATE\\s+PROCEDURE"}, nil, Ignore}, 30 {"cdc", "t1", []EventType{RebaseAutoID}, nil, nil, Ignore}, 31 } 32 33 cases := []struct { 34 schema, table string 35 event EventType 36 sql string 37 action ActionType 38 }{ 39 {"test_1_a", "abc1", DeleteEvent, "", Ignore}, 40 {"test_1_a", "abc1", InsertEvent, "", Ignore}, 41 {"test_1_a", "abc1", UpdateEvent, "", Do}, 42 {"test_1_a", "abc1", CreateIndex, "", Ignore}, 43 {"test_1_a", "abc1", RenameTable, "", Do}, 44 {"test_1_a", "abc1", NullEvent, "drop procedure abc", Ignore}, 45 {"test_1_a", "abc1", NullEvent, "create procedure abc", Ignore}, 46 {"test_1_a", "abc1", NullEvent, "create function abc", Do}, 47 {"xxx_1", "abc_1", NullEvent, "create function abc", Do}, 48 {"xxx_1", "abc_1", InsertEvent, "", Ignore}, 49 {"xxx_1", "abc_1", CreateIndex, "", Do}, 50 {"yyy_1", "abc_1", InsertEvent, "", Do}, 51 {"yyy_1", "abc_1", CreateIndex, "", Ignore}, 52 {"test_1_a", "abc1", DropView, "", Ignore}, 53 {"cdc", "t1", RebaseAutoID, "", Ignore}, 54 } 55 56 // initial binlog event filter 57 filter, err := NewBinlogEvent(false, rules) 58 require.NoError(t, err) 59 60 // insert duplicate rules 61 for _, rule := range rules { 62 err = filter.AddRule(rule) 63 require.Error(t, err) 64 } 65 for _, cs := range cases { 66 action, err := filter.Filter(cs.schema, cs.table, cs.event, cs.sql) 67 require.NoError(t, err) 68 require.Equal(t, cs.action, action) 69 } 70 71 // update rules 72 rules[0].Events = []EventType{} 73 rules[1].Action = Do 74 rules[2].Events = []EventType{"ALL DDL"} 75 rules = rules[:3] 76 for _, rule := range rules { 77 err = filter.UpdateRule(rule) 78 require.NoError(t, err) 79 } 80 81 cases[0].action = Do // delete 82 cases[1].action = Do // insert 83 cases[3].action = Do // create index 84 cases[9].action = Do // match all event and insert 85 cases[10].action = Ignore // match none event and create index 86 cases[11].action = Ignore // no match 87 cases[12].action = Do // match all ddl 88 cases[13].action = Do // match all ddl 89 for _, cs := range cases { 90 action, err := filter.Filter(cs.schema, cs.table, cs.event, cs.sql) 91 require.NoError(t, err) 92 require.Equal(t, cs.action, action) 93 } 94 95 // test multiple rules 96 rule := &BinlogEventRule{"test_*", "ab*", []EventType{InsertEvent, AllDDL}, []string{"^DROP\\s+PROCEDURE"}, nil, Do} 97 err = filter.AddRule(rule) 98 require.NoError(t, err) 99 cases[0].action = Ignore // delete 100 cases[2].action = Ignore // update 101 cases[4].action = Do // rename table 102 cases[7].action = Ignore // create function 103 for _, cs := range cases { 104 action, err := filter.Filter(cs.schema, cs.table, cs.event, cs.sql) 105 require.NoError(t, err) 106 require.Equal(t, cs.action, action) 107 } 108 109 // remove rule 110 err = filter.RemoveRule(rules[0]) 111 require.NoError(t, err) 112 // remove not existing rule 113 err = filter.RemoveRule(rules[0]) 114 require.Error(t, err) 115 cases[3].action = Do // create index 116 cases[5].action = Do // drop procedure 117 for _, cs := range cases { 118 action, err := filter.Filter(cs.schema, cs.table, cs.event, cs.sql) 119 require.NoError(t, err) 120 require.Equal(t, cs.action, action) 121 } 122 123 // mismatched 124 action, err := filter.Filter("xxx_a", "", InsertEvent, "") 125 require.NoError(t, err) 126 require.Equal(t, Do, action) 127 128 // invalid rule 129 err = filter.Selector.Insert("test_1_*", "abc*", "error", selector.Insert) 130 require.NoError(t, err) 131 _, err = filter.Filter("test_1_a", "abc", InsertEvent, "") 132 require.Error(t, err) 133 } 134 135 func TestCaseSensitive(t *testing.T) { 136 // we test case insensitive in TestFilter 137 rules := []*BinlogEventRule{ 138 {"Test_1_*", "abc*", []EventType{DeleteEvent, InsertEvent, CreateIndex, DropIndex}, []string{"^DROP\\s+PROCEDURE", "^CREATE\\s+PROCEDURE"}, nil, Ignore}, 139 {"xxx_*", "abc_*", []EventType{AllDML, NoneDDL}, nil, nil, Ignore}, 140 } 141 142 cases := []struct { 143 schema, table string 144 event EventType 145 sql string 146 action ActionType 147 }{ 148 {"test_1_a", "abc1", DeleteEvent, "", Do}, 149 {"test_1_a", "abc1", InsertEvent, "", Do}, 150 {"test_1_a", "abc1", UpdateEvent, "", Do}, 151 {"test_1_a", "abc1", CreateIndex, "", Do}, 152 {"test_1_a", "abc1", RenameTable, "", Do}, 153 {"test_1_a", "abc1", NullEvent, "drop procedure abc", Do}, 154 {"test_1_a", "abc1", NullEvent, "create procedure abc", Do}, 155 {"test_1_a", "abc1", NullEvent, "create function abc", Do}, 156 {"xxx_1", "abc_1", NullEvent, "create function abc", Do}, 157 {"xxx_1", "abc_1", InsertEvent, "", Ignore}, 158 {"xxx_1", "abc_1", CreateIndex, "", Do}, 159 } 160 161 // initial binlog event filter 162 filter, err := NewBinlogEvent(true, rules) 163 require.NoError(t, err) 164 165 // insert duplicate rules 166 for _, rule := range rules { 167 err = filter.AddRule(rule) 168 require.Error(t, err) 169 } 170 for _, cs := range cases { 171 action, err := filter.Filter(cs.schema, cs.table, cs.event, cs.sql) 172 require.NoError(t, err) 173 require.Equal(t, cs.action, action) 174 } 175 } 176 177 func TestGlobalFilter(t *testing.T) { 178 schemaRule := &BinlogEventRule{ 179 SchemaPattern: "*", 180 SQLPattern: []string{"^FLUSH"}, 181 Action: Ignore, 182 } 183 tableRule := &BinlogEventRule{ 184 SchemaPattern: "*", 185 TablePattern: "*", 186 SQLPattern: []string{"^FLUSH"}, 187 Action: Ignore, 188 } 189 190 cases := []struct { 191 schema string 192 table string 193 sql string 194 action ActionType 195 }{ 196 { 197 schema: "db", 198 table: "tbl", 199 sql: "FLUSH ENGINE LOGS", 200 action: Ignore, 201 }, 202 { 203 schema: "db", 204 table: "", 205 sql: "FLUSH ENGINE LOGS", 206 action: Ignore, 207 }, 208 { 209 schema: "", 210 table: "tbl", 211 sql: "FLUSH ENGINE LOGS", 212 action: Ignore, 213 }, 214 { 215 schema: "", 216 table: "", 217 sql: "FLUSH ENGINE LOGS", 218 action: Ignore, 219 }, 220 } 221 222 // initial binlog event filter with schema rule 223 filter, err := NewBinlogEvent(false, []*BinlogEventRule{schemaRule}) 224 require.NoError(t, err) 225 226 for _, cs := range cases { 227 action, err := filter.Filter(cs.schema, cs.table, NullEvent, cs.sql) 228 require.NoError(t, err) 229 require.Equal(t, cs.action, action) 230 } 231 232 // remove schema rule 233 err = filter.RemoveRule(schemaRule) 234 require.NoError(t, err) 235 236 // add table rule 237 err = filter.AddRule(tableRule) 238 require.NoError(t, err) 239 240 for _, cs := range cases { 241 action, err := filter.Filter(cs.schema, cs.table, NullEvent, cs.sql) 242 require.NoError(t, err) 243 require.Equal(t, cs.action, action) 244 } 245 } 246 247 func TestToEventType(t *testing.T) { 248 cases := []struct { 249 eventStr string 250 event EventType 251 err error 252 }{ 253 {"", NullEvent, nil}, 254 {"insert", InsertEvent, nil}, 255 {"Insert", InsertEvent, nil}, 256 {"update", UpdateEvent, nil}, 257 {"UPDATE", UpdateEvent, nil}, 258 {"delete", DeleteEvent, nil}, 259 {"create", NullEvent, errors.NotValidf("event type %s", "create")}, 260 {"create schema", CreateDatabase, nil}, 261 {"create SCHEMA", CreateDatabase, nil}, 262 {"create database", CreateDatabase, nil}, 263 {"drop schema", DropDatabase, nil}, 264 {"drop Schema", DropDatabase, nil}, 265 {"drop database", DropDatabase, nil}, 266 {"alter database", AlterDatabase, nil}, 267 {"alter schema", AlterDatabase, nil}, 268 {"create index", CreateIndex, nil}, 269 {"add table partition", AddTablePartition, nil}, 270 {"drop taBle partition", DropTablePartition, nil}, 271 {"truncate tablE parTition", TruncateTablePartition, nil}, 272 {"rebase auto id", RebaseAutoID, nil}, 273 {"xxx", NullEvent, errors.NotValidf("event type %s", "xxx")}, 274 {"I don't know", NullEvent, errors.NotValidf("event type %s", "I don't know")}, 275 } 276 277 for _, cs := range cases { 278 event, err := toEventType(cs.eventStr) 279 require.Equal(t, cs.event, event) 280 if err != nil { 281 require.ErrorContains(t, err, cs.err.Error()) 282 } else { 283 require.NoError(t, err) 284 } 285 } 286 } 287 288 func TestClassifyEvent(t *testing.T) { 289 cases := []struct { 290 event EventType 291 evenType EventType 292 err error 293 }{ 294 {NullEvent, NullEvent, nil}, 295 // dml 296 {InsertEvent, dml, nil}, 297 {UpdateEvent, dml, nil}, 298 {DeleteEvent, dml, nil}, 299 // ddl 300 {CreateDatabase, ddl, nil}, 301 {CreateSchema, ddl, nil}, 302 {DropDatabase, incompatibleDDL, nil}, 303 {DropSchema, incompatibleDDL, nil}, 304 {AlterSchema, ddl, nil}, 305 {CreateTable, ddl, nil}, 306 {DropTable, incompatibleDDL, nil}, 307 {TruncateTable, incompatibleDDL, nil}, 308 {RenameTable, incompatibleDDL, nil}, 309 {CreateIndex, ddl, nil}, 310 {DropIndex, incompatibleDDL, nil}, 311 {CreateView, ddl, nil}, 312 {DropView, ddl, nil}, 313 {AlterTable, ddl, nil}, 314 {AddTablePartition, ddl, nil}, 315 {DropTablePartition, incompatibleDDL, nil}, 316 {RebaseAutoID, incompatibleDDL, nil}, 317 {TruncateTablePartition, incompatibleDDL, nil}, 318 {"create", NullEvent, errors.NotValidf("event type %s", "create")}, 319 {EventType("xxx"), NullEvent, errors.NotValidf("event type %s", "xxx")}, 320 {EventType("I don't know"), NullEvent, errors.NotValidf("event type %s", "I don't know")}, 321 } 322 323 for _, cs := range cases { 324 et, err := ClassifyEvent(cs.event) 325 require.Equal(t, cs.evenType, et) 326 if err != nil { 327 require.ErrorContains(t, err, cs.err.Error()) 328 } else { 329 require.NoError(t, err) 330 } 331 } 332 }