github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/sink/codec/canal/canal_encoder_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 canal
    15  
    16  import (
    17  	"context"
    18  	"testing"
    19  
    20  	"github.com/golang/protobuf/proto"
    21  	"github.com/pingcap/tiflow/cdc/entry"
    22  	"github.com/pingcap/tiflow/cdc/model"
    23  	"github.com/pingcap/tiflow/pkg/config"
    24  	"github.com/pingcap/tiflow/pkg/sink/codec/common"
    25  	canal "github.com/pingcap/tiflow/proto/canal"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  func TestCanalBatchEncoder(t *testing.T) {
    30  	helper := entry.NewSchemaTestHelper(t)
    31  	defer helper.Close()
    32  
    33  	sql := `create table test.t(a varchar(10) primary key)`
    34  	_ = helper.DDL2Event(sql)
    35  
    36  	event1 := helper.DML2Event(`insert into test.t values("aa")`, "test", "t")
    37  	event2 := helper.DML2Event(`insert into test.t values("bb")`, "test", "t")
    38  
    39  	rowCases := [][]*model.RowChangedEvent{
    40  		{event1},
    41  		{event1, event2},
    42  	}
    43  
    44  	ctx := context.Background()
    45  	encoder := newBatchEncoder(common.NewConfig(config.ProtocolCanal))
    46  	for _, cs := range rowCases {
    47  		for _, event := range cs {
    48  			err := encoder.AppendRowChangedEvent(ctx, "", event, nil)
    49  			require.NoError(t, err)
    50  		}
    51  		res := encoder.Build()
    52  		require.Len(t, res, 1)
    53  		require.Nil(t, res[0].Key)
    54  		require.Equal(t, len(cs), res[0].GetRowsCount())
    55  
    56  		packet := &canal.Packet{}
    57  		err := proto.Unmarshal(res[0].Value, packet)
    58  		require.Nil(t, err)
    59  		require.Equal(t, canal.PacketType_MESSAGES, packet.GetType())
    60  		messages := &canal.Messages{}
    61  		err = proto.Unmarshal(packet.GetBody(), messages)
    62  		require.Nil(t, err)
    63  		require.Equal(t, len(cs), len(messages.GetMessages()))
    64  	}
    65  
    66  	createTableA := helper.DDL2Event(`create table test.a(a varchar(10) primary key)`)
    67  	createTableB := helper.DDL2Event(`create table test.b(a varchar(10) primary key)`)
    68  
    69  	ddlCases := [][]*model.DDLEvent{
    70  		{createTableA},
    71  		{createTableA, createTableB},
    72  	}
    73  	for _, cs := range ddlCases {
    74  		encoder := newBatchEncoder(common.NewConfig(config.ProtocolCanal))
    75  		for _, ddl := range cs {
    76  			msg, err := encoder.EncodeDDLEvent(ddl)
    77  			require.NoError(t, err)
    78  			require.NotNil(t, msg)
    79  			require.Nil(t, msg.Key)
    80  
    81  			packet := &canal.Packet{}
    82  			err = proto.Unmarshal(msg.Value, packet)
    83  			require.NoError(t, err)
    84  			require.Equal(t, canal.PacketType_MESSAGES, packet.GetType())
    85  			messages := &canal.Messages{}
    86  			err = proto.Unmarshal(packet.GetBody(), messages)
    87  			require.NoError(t, err)
    88  			require.Equal(t, 1, len(messages.GetMessages()))
    89  			require.NoError(t, err)
    90  		}
    91  	}
    92  }
    93  
    94  func TestCanalAppendRowChangedEventWithCallback(t *testing.T) {
    95  	helper := entry.NewSchemaTestHelper(t)
    96  	defer helper.Close()
    97  
    98  	sql := `create table test.t(a varchar(10) primary key)`
    99  	_ = helper.DDL2Event(sql)
   100  
   101  	row := helper.DML2Event(`insert into test.t values("aa")`, "test", "t")
   102  	encoder := newBatchEncoder(common.NewConfig(config.ProtocolCanal))
   103  	require.NotNil(t, encoder)
   104  
   105  	count := 0
   106  
   107  	tests := []struct {
   108  		row      *model.RowChangedEvent
   109  		callback func()
   110  	}{
   111  		{
   112  			row: row,
   113  			callback: func() {
   114  				count += 1
   115  			},
   116  		},
   117  		{
   118  			row: row,
   119  			callback: func() {
   120  				count += 2
   121  			},
   122  		},
   123  		{
   124  			row: row,
   125  			callback: func() {
   126  				count += 3
   127  			},
   128  		},
   129  		{
   130  			row: row,
   131  			callback: func() {
   132  				count += 4
   133  			},
   134  		},
   135  		{
   136  			row: row,
   137  			callback: func() {
   138  				count += 5
   139  			},
   140  		},
   141  	}
   142  
   143  	// Empty build makes sure that the callback build logic not broken.
   144  	msgs := encoder.Build()
   145  	require.Len(t, msgs, 0, "no message should be built and no panic")
   146  
   147  	// Append the events.
   148  	for _, test := range tests {
   149  		err := encoder.AppendRowChangedEvent(context.Background(), "", test.row, test.callback)
   150  		require.Nil(t, err)
   151  	}
   152  	require.Equal(t, 0, count, "nothing should be called")
   153  
   154  	msgs = encoder.Build()
   155  	require.Len(t, msgs, 1, "expected one message")
   156  	msgs[0].Callback()
   157  	require.Equal(t, 15, count, "expected all callbacks to be called")
   158  }