github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/sink/codec/canal_flat_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 codec 15 16 import ( 17 "encoding/json" 18 19 "github.com/pingcap/check" 20 mm "github.com/pingcap/parser/model" 21 "github.com/pingcap/parser/mysql" 22 "github.com/pingcap/ticdc/cdc/model" 23 "github.com/pingcap/ticdc/pkg/util/testleak" 24 "golang.org/x/text/encoding/charmap" 25 ) 26 27 type canalFlatSuite struct { 28 } 29 30 var _ = check.Suite(&canalFlatSuite{}) 31 32 func (s *canalFlatSuite) TestNewCanalFlatMessageFromDML(c *check.C) { 33 defer testleak.AfterTest(c)() 34 encoder := &CanalFlatEventBatchEncoder{builder: NewCanalEntryBuilder()} 35 c.Assert(encoder, check.NotNil) 36 msg, err := encoder.newFlatMessageForDML(testCaseUpdate) 37 c.Assert(err, check.IsNil) 38 39 c.Assert(msg.EventType, check.Equals, "UPDATE") 40 c.Assert(msg.ExecutionTime, check.Equals, convertToCanalTs(testCaseUpdate.CommitTs)) 41 c.Assert(msg.tikvTs, check.Equals, testCaseUpdate.CommitTs) 42 c.Assert(msg.Schema, check.Equals, "cdc") 43 c.Assert(msg.Table, check.Equals, "person") 44 c.Assert(msg.IsDDL, check.IsFalse) 45 c.Assert(msg.SQLType, check.DeepEquals, map[string]int32{ 46 "id": int32(JavaSQLTypeBIGINT), 47 "name": int32(JavaSQLTypeVARCHAR), 48 "tiny": int32(JavaSQLTypeSMALLINT), 49 "comment": int32(JavaSQLTypeVARCHAR), 50 "blob": int32(JavaSQLTypeBLOB), 51 }) 52 c.Assert(msg.MySQLType, check.DeepEquals, map[string]string{ 53 "id": "int", 54 "name": "varchar", 55 "tiny": "tinyint", 56 "comment": "text", 57 "blob": "blob", 58 }) 59 encodedBytes, err := charmap.ISO8859_1.NewDecoder().Bytes([]byte("测试blob")) 60 c.Assert(err, check.IsNil) 61 c.Assert(msg.Data, check.DeepEquals, []map[string]interface{}{ 62 { 63 "id": "1", 64 "name": "Bob", 65 "tiny": "255", 66 "comment": "测试", 67 "blob": string(encodedBytes), 68 }, 69 }) 70 c.Assert(msg.Old, check.DeepEquals, []map[string]interface{}{ 71 { 72 "id": "1", 73 "name": "Alice", 74 "tiny": "255", 75 "comment": "测试", 76 "blob": string(encodedBytes), 77 }, 78 }) 79 } 80 81 func (s *canalFlatSuite) TestNewCanalFlatMessageFromDDL(c *check.C) { 82 defer testleak.AfterTest(c)() 83 encoder := &CanalFlatEventBatchEncoder{builder: NewCanalEntryBuilder()} 84 c.Assert(encoder, check.NotNil) 85 86 msg := encoder.newFlatMessageForDDL(testCaseDdl) 87 c.Assert(msg, check.NotNil) 88 89 c.Assert(msg.tikvTs, check.Equals, testCaseDdl.CommitTs) 90 c.Assert(msg.ExecutionTime, check.Equals, convertToCanalTs(testCaseDdl.CommitTs)) 91 c.Assert(msg.IsDDL, check.IsTrue) 92 c.Assert(msg.Schema, check.Equals, "cdc") 93 c.Assert(msg.Table, check.Equals, "person") 94 c.Assert(msg.Query, check.Equals, testCaseDdl.Query) 95 c.Assert(msg.EventType, check.Equals, "CREATE") 96 } 97 98 func (s *canalFlatSuite) TestBatching(c *check.C) { 99 defer testleak.AfterTest(c)() 100 encoder := &CanalFlatEventBatchEncoder{builder: NewCanalEntryBuilder()} 101 c.Assert(encoder, check.NotNil) 102 103 updateCase := *testCaseUpdate 104 lastResolved := uint64(0) 105 for i := 1; i < 1000; i++ { 106 ts := uint64(i) 107 updateCase.CommitTs = ts 108 result, err := encoder.AppendRowChangedEvent(&updateCase) 109 c.Assert(err, check.IsNil) 110 c.Assert(result, check.Equals, EncoderNoOperation) 111 112 if i >= 100 && (i%100 == 0 || i == 999) { 113 resolvedTs := uint64(i - 50) 114 if i == 999 { 115 resolvedTs = 999 116 } 117 result, err := encoder.AppendResolvedEvent(resolvedTs) 118 119 c.Assert(err, check.IsNil) 120 c.Assert(result, check.Equals, EncoderNeedAsyncWrite) 121 122 msgs := encoder.Build() 123 c.Assert(msgs, check.NotNil) 124 c.Assert(msgs, check.HasLen, int(resolvedTs-lastResolved)) 125 126 for j := range msgs { 127 var msg canalFlatMessage 128 err := json.Unmarshal(msgs[j].Value, &msg) 129 c.Assert(err, check.IsNil) 130 c.Assert(msg.EventType, check.Equals, "UPDATE") 131 c.Assert(msg.ExecutionTime, check.Equals, convertToCanalTs(lastResolved+uint64(i))) 132 } 133 134 lastResolved = resolvedTs 135 } 136 } 137 138 c.Assert(encoder.unresolvedBuf, check.HasLen, 0) 139 c.Assert(encoder.resolvedBuf, check.HasLen, 0) 140 } 141 142 var testCaseUpdate = &model.RowChangedEvent{ 143 CommitTs: 417318403368288260, 144 Table: &model.TableName{ 145 Schema: "cdc", 146 Table: "person", 147 }, 148 Columns: []*model.Column{ 149 {Name: "id", Type: mysql.TypeLong, Flag: model.PrimaryKeyFlag, Value: 1}, 150 {Name: "name", Type: mysql.TypeVarchar, Value: "Bob"}, 151 {Name: "tiny", Type: mysql.TypeTiny, Value: 255}, 152 {Name: "comment", Type: mysql.TypeBlob, Value: []byte("测试")}, 153 {Name: "blob", Type: mysql.TypeBlob, Value: []byte("测试blob"), Flag: model.BinaryFlag}, 154 }, 155 PreColumns: []*model.Column{ 156 {Name: "id", Type: mysql.TypeLong, Flag: model.HandleKeyFlag, Value: 1}, 157 {Name: "name", Type: mysql.TypeVarchar, Value: "Alice"}, 158 {Name: "tiny", Type: mysql.TypeTiny, Value: 255}, 159 {Name: "comment", Type: mysql.TypeBlob, Value: []byte("测试")}, 160 {Name: "blob", Type: mysql.TypeBlob, Value: []byte("测试blob"), Flag: model.BinaryFlag}, 161 }, 162 } 163 164 var testCaseDdl = &model.DDLEvent{ 165 CommitTs: 417318403368288260, 166 TableInfo: &model.SimpleTableInfo{ 167 Schema: "cdc", Table: "person", 168 }, 169 Query: "create table person(id int, name varchar(32), tiny tinyint unsigned, comment text, primary key(id))", 170 Type: mm.ActionCreateTable, 171 }