github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/syncer/dml_worker_test.go (about)

     1  // Copyright 2022 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 syncer
    15  
    16  import (
    17  	"testing"
    18  
    19  	tiddl "github.com/pingcap/tidb/pkg/ddl"
    20  	"github.com/pingcap/tidb/pkg/parser"
    21  	"github.com/pingcap/tidb/pkg/parser/ast"
    22  	timodel "github.com/pingcap/tidb/pkg/parser/model"
    23  	timock "github.com/pingcap/tidb/pkg/util/mock"
    24  	cdcmodel "github.com/pingcap/tiflow/cdc/model"
    25  	"github.com/pingcap/tiflow/pkg/sqlmodel"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  func mockTableInfo(t *testing.T, sql string) *timodel.TableInfo {
    30  	t.Helper()
    31  
    32  	p := parser.New()
    33  	se := timock.NewContext()
    34  	node, err := p.ParseOneStmt(sql, "", "")
    35  	require.NoError(t, err)
    36  	ti, err := tiddl.MockTableInfo(se, node.(*ast.CreateTableStmt), 1)
    37  	require.NoError(t, err)
    38  	return ti
    39  }
    40  
    41  func TestGenSQL(t *testing.T) {
    42  	t.Parallel()
    43  
    44  	source := &cdcmodel.TableName{Schema: "db", Table: "tb"}
    45  	target := &cdcmodel.TableName{Schema: "targetSchema", Table: "targetTable"}
    46  	createSQL := "create table db.tb(id int primary key, col1 int unique not null, col2 int unique, name varchar(24))"
    47  
    48  	cases := []struct {
    49  		preValues  []interface{}
    50  		postValues []interface{}
    51  		safeMode   bool
    52  
    53  		expectedSQLs []string
    54  		expectedArgs [][]interface{}
    55  	}{
    56  		{
    57  			nil,
    58  			[]interface{}{1, 2, 3, "haha"},
    59  			false,
    60  
    61  			[]string{"INSERT INTO `targetSchema`.`targetTable` (`id`,`col1`,`col2`,`name`) VALUES (?,?,?,?)"},
    62  			[][]interface{}{{1, 2, 3, "haha"}},
    63  		},
    64  		{
    65  			nil,
    66  			[]interface{}{1, 2, 3, "haha"},
    67  			true,
    68  
    69  			[]string{"REPLACE INTO `targetSchema`.`targetTable` (`id`,`col1`,`col2`,`name`) VALUES (?,?,?,?)"},
    70  			[][]interface{}{{1, 2, 3, "haha"}},
    71  		},
    72  		{
    73  			[]interface{}{1, 2, 3, "haha"},
    74  			nil,
    75  			false,
    76  
    77  			[]string{"DELETE FROM `targetSchema`.`targetTable` WHERE `id` = ? LIMIT 1"},
    78  			[][]interface{}{{1}},
    79  		},
    80  		{
    81  			[]interface{}{1, 2, 3, "haha"},
    82  			[]interface{}{4, 5, 6, "hihi"},
    83  			false,
    84  
    85  			[]string{"UPDATE `targetSchema`.`targetTable` SET `id` = ?, `col1` = ?, `col2` = ?, `name` = ? WHERE `id` = ? LIMIT 1"},
    86  			[][]interface{}{{4, 5, 6, "hihi", 1}},
    87  		},
    88  		{
    89  			[]interface{}{1, 2, 3, "haha"},
    90  			[]interface{}{4, 5, 6, "hihi"},
    91  			true,
    92  
    93  			[]string{"DELETE FROM `targetSchema`.`targetTable` WHERE `id` = ? LIMIT 1", "REPLACE INTO `targetSchema`.`targetTable` (`id`,`col1`,`col2`,`name`) VALUES (?,?,?,?)"},
    94  			[][]interface{}{{1}, {4, 5, 6, "hihi"}},
    95  		},
    96  	}
    97  
    98  	worker := &DMLWorker{}
    99  
   100  	for _, c := range cases {
   101  		tableInfo := mockTableInfo(t, createSQL)
   102  		change := sqlmodel.NewRowChange(source, target, c.preValues, c.postValues, tableInfo, nil, nil)
   103  		testEC := ec
   104  		if c.safeMode {
   105  			testEC = ecWithSafeMode
   106  		}
   107  		dmlJob := newDMLJob(change, testEC)
   108  		queries, args := worker.genSQLs([]*job{dmlJob})
   109  		require.Equal(t, c.expectedSQLs, queries)
   110  		require.Equal(t, c.expectedArgs, args)
   111  	}
   112  }
   113  
   114  func TestJudgeKeyNotFound(t *testing.T) {
   115  	dmlWorker := &DMLWorker{
   116  		compact:      true,
   117  		multipleRows: true,
   118  	}
   119  	require.False(t, dmlWorker.judgeKeyNotFound(0, nil))
   120  	dmlWorker.compact = false
   121  	require.False(t, dmlWorker.judgeKeyNotFound(0, nil))
   122  	dmlWorker.multipleRows = false
   123  	require.False(t, dmlWorker.judgeKeyNotFound(0, nil))
   124  	jobs := []*job{{safeMode: false}, {safeMode: true}}
   125  	require.False(t, dmlWorker.judgeKeyNotFound(0, jobs))
   126  	jobs[1].safeMode = false
   127  	require.True(t, dmlWorker.judgeKeyNotFound(0, jobs))
   128  	require.False(t, dmlWorker.judgeKeyNotFound(2, jobs))
   129  	require.False(t, dmlWorker.judgeKeyNotFound(4, jobs))
   130  }