github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/model/codec/codec_test.go (about)

     1  // Copyright 2023 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  	"testing"
    18  
    19  	"github.com/pingcap/tidb/pkg/parser/charset"
    20  	timodel "github.com/pingcap/tidb/pkg/parser/model"
    21  	"github.com/pingcap/tidb/pkg/parser/mysql"
    22  	"github.com/pingcap/tiflow/cdc/model"
    23  	codecv1 "github.com/pingcap/tiflow/cdc/model/codec/v1"
    24  	"github.com/stretchr/testify/require"
    25  )
    26  
    27  func TestV1toV2(t *testing.T) {
    28  	var msg1 []byte
    29  	var rv1 *codecv1.RedoLog
    30  	var rv2, rv2Gen *model.RedoLog
    31  	var err error
    32  
    33  	rv1 = &codecv1.RedoLog{
    34  		RedoRow: &codecv1.RedoRowChangedEvent{
    35  			Row: &codecv1.RowChangedEvent{
    36  				StartTs:  1,
    37  				CommitTs: 2,
    38  				Table: &codecv1.TableName{
    39  					Schema:      "schema",
    40  					Table:       "table",
    41  					TableID:     1,
    42  					IsPartition: false,
    43  				},
    44  				TableInfo: nil,
    45  				Columns: []*codecv1.Column{
    46  					{
    47  						Name: "column",
    48  						Flag: model.BinaryFlag,
    49  					},
    50  				},
    51  				PreColumns: []*codecv1.Column{
    52  					{
    53  						Name: "column",
    54  						Flag: model.BinaryFlag,
    55  					},
    56  				},
    57  				IndexColumns: [][]int{{1}},
    58  			},
    59  		},
    60  		RedoDDL: &codecv1.RedoDDLEvent{
    61  			DDL: &codecv1.DDLEvent{
    62  				StartTs:  1,
    63  				CommitTs: 2,
    64  				Type:     timodel.ActionCreateTable,
    65  			},
    66  		},
    67  	}
    68  
    69  	rv2 = &model.RedoLog{
    70  		RedoRow: model.RedoRowChangedEvent{
    71  			Row: &model.RowChangedEventInRedoLog{
    72  				StartTs:  1,
    73  				CommitTs: 2,
    74  				Table: &model.TableName{
    75  					Schema:      "schema",
    76  					Table:       "table",
    77  					TableID:     1,
    78  					IsPartition: false,
    79  				},
    80  				Columns: []*model.Column{
    81  					{
    82  						Name: "column",
    83  						Flag: model.BinaryFlag,
    84  					},
    85  				},
    86  				PreColumns: []*model.Column{
    87  					{
    88  						Name: "column",
    89  						Flag: model.BinaryFlag,
    90  					},
    91  				},
    92  				IndexColumns: [][]int{{1}},
    93  			},
    94  		},
    95  		RedoDDL: model.RedoDDLEvent{
    96  			DDL: &model.DDLEvent{
    97  				StartTs:  1,
    98  				CommitTs: 2,
    99  				Type:     timodel.ActionCreateTable,
   100  			},
   101  		},
   102  	}
   103  
   104  	// Unmarshal from v1, []byte{} will be transformed into "".
   105  	rv1.RedoRow.Row.Columns[0].Value = []byte{}
   106  	rv1.RedoRow.Row.PreColumns[0].Value = []byte{}
   107  	rv2.RedoRow.Row.Columns[0].Value = ""
   108  	rv2.RedoRow.Row.PreColumns[0].Value = ""
   109  
   110  	// Marshal v1 into bytes.
   111  	codecv1.PreMarshal(rv1)
   112  	msg1, err = rv1.MarshalMsg(nil)
   113  	require.Nil(t, err)
   114  
   115  	// Unmarshal v2 from v1 bytes.
   116  	rv2Gen, msg1, err = UnmarshalRedoLog(msg1)
   117  	require.Nil(t, err)
   118  	require.Zero(t, len(msg1))
   119  	require.Equal(t, rv2.RedoRow.Row, rv2Gen.RedoRow.Row)
   120  
   121  	// For v2, []byte{} will be kept same in marshal and unmarshal.
   122  	rv2.RedoRow.Row.Columns[0].Value = []byte{}
   123  	rv2.RedoRow.Row.PreColumns[0].Value = []byte{}
   124  	rv2Gen.RedoRow.Row.Columns[0].Value = []byte{}
   125  	rv2Gen.RedoRow.Row.PreColumns[0].Value = []byte{}
   126  
   127  	msg1, err = MarshalRedoLog(rv2Gen, nil)
   128  	require.Nil(t, err)
   129  	rv2Gen, msg1, err = UnmarshalRedoLog(msg1)
   130  	require.Nil(t, err)
   131  	require.Zero(t, len(msg1))
   132  	require.Equal(t, rv2.RedoRow.Row, rv2Gen.RedoRow.Row)
   133  }
   134  
   135  func TestRowRedoConvert(t *testing.T) {
   136  	t.Parallel()
   137  
   138  	row := &model.RowChangedEventInRedoLog{
   139  		StartTs:  100,
   140  		CommitTs: 120,
   141  		Table:    &model.TableName{Schema: "test", Table: "table1", TableID: 57},
   142  		PreColumns: []*model.Column{{
   143  			Name:  "a1",
   144  			Type:  mysql.TypeLong,
   145  			Flag:  model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag,
   146  			Value: int64(1),
   147  		}, {
   148  			Name:  "a2",
   149  			Type:  mysql.TypeVarchar,
   150  			Value: []byte("char"),
   151  		}, {
   152  			Name:  "a3",
   153  			Type:  mysql.TypeLong,
   154  			Flag:  model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag,
   155  			Value: int64(1),
   156  		}, {
   157  			Name:    "a4",
   158  			Type:    mysql.TypeTinyBlob,
   159  			Charset: charset.CharsetGBK,
   160  			Value:   []byte("你好"),
   161  		}, nil},
   162  		Columns: []*model.Column{{
   163  			Name:  "a1",
   164  			Type:  mysql.TypeLong,
   165  			Flag:  model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag,
   166  			Value: int64(2),
   167  		}, {
   168  			Name:  "a2",
   169  			Type:  mysql.TypeVarchar,
   170  			Value: []byte("char-updated"),
   171  		}, {
   172  			Name:  "a3",
   173  			Type:  mysql.TypeLong,
   174  			Flag:  model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag,
   175  			Value: int64(2),
   176  		}, {
   177  			Name:    "a4",
   178  			Type:    mysql.TypeTinyBlob,
   179  			Charset: charset.CharsetGBK,
   180  			Value:   []byte("世界"),
   181  		}, nil},
   182  		IndexColumns: [][]int{{1, 3}},
   183  	}
   184  
   185  	redoLog := &model.RedoLog{RedoRow: model.RedoRowChangedEvent{Row: row}}
   186  	data, err := MarshalRedoLog(redoLog, nil)
   187  	require.Nil(t, err)
   188  
   189  	redoLog2, data, err := UnmarshalRedoLog(data)
   190  	require.Nil(t, err)
   191  	require.Zero(t, len(data))
   192  	require.Equal(t, row, redoLog2.RedoRow.Row)
   193  }
   194  
   195  func TestRowRedoConvertWithEmptySlice(t *testing.T) {
   196  	t.Parallel()
   197  
   198  	row := &model.RowChangedEventInRedoLog{
   199  		StartTs:  100,
   200  		CommitTs: 120,
   201  		Table:    &model.TableName{Schema: "test", Table: "table1", TableID: 57},
   202  		PreColumns: []*model.Column{{
   203  			Name:  "a1",
   204  			Type:  mysql.TypeLong,
   205  			Flag:  model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag,
   206  			Value: int64(1),
   207  		}, {
   208  			Name:  "a2",
   209  			Type:  mysql.TypeVarchar,
   210  			Value: []byte(""), // empty slice should be marshal and unmarshal safely
   211  		}},
   212  		Columns: []*model.Column{{
   213  			Name:  "a1",
   214  			Type:  mysql.TypeLong,
   215  			Flag:  model.BinaryFlag | model.MultipleKeyFlag | model.HandleKeyFlag,
   216  			Value: int64(2),
   217  		}, {
   218  			Name:  "a2",
   219  			Type:  mysql.TypeVarchar,
   220  			Value: []byte(""),
   221  		}},
   222  		IndexColumns: [][]int{{1}},
   223  	}
   224  
   225  	redoLog := &model.RedoLog{RedoRow: model.RedoRowChangedEvent{Row: row}}
   226  	data, err := MarshalRedoLog(redoLog, nil)
   227  	require.Nil(t, err)
   228  
   229  	redoLog2, data, err := UnmarshalRedoLog(data)
   230  	require.Nil(t, err)
   231  	require.Zero(t, len(data))
   232  	require.Equal(t, row, redoLog2.RedoRow.Row)
   233  }
   234  
   235  func TestDDLRedoConvert(t *testing.T) {
   236  	t.Parallel()
   237  
   238  	ddl := &model.DDLEvent{
   239  		StartTs:   1020,
   240  		CommitTs:  1030,
   241  		TableInfo: &model.TableInfo{},
   242  		Type:      timodel.ActionAddColumn,
   243  		Query:     "ALTER TABLE test.t1 ADD COLUMN a int",
   244  	}
   245  
   246  	redoLog := &model.RedoLog{RedoDDL: model.RedoDDLEvent{DDL: ddl}}
   247  	data, err := MarshalRedoLog(redoLog, nil)
   248  	require.Nil(t, err)
   249  
   250  	redoLog2, data, err := UnmarshalRedoLog(data)
   251  	require.Nil(t, err)
   252  	require.Zero(t, len(data))
   253  	require.Equal(t, ddl, redoLog2.RedoDDL.DDL)
   254  }