github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/unit/unit_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 unit 15 16 import ( 17 "context" 18 "database/sql/driver" 19 "testing" 20 21 "github.com/go-sql-driver/mysql" 22 "github.com/pingcap/check" 23 "github.com/pingcap/errors" 24 "github.com/pingcap/tidb/pkg/lightning/common" 25 tmysql "github.com/pingcap/tidb/pkg/parser/mysql" 26 "github.com/pingcap/tiflow/dm/pb" 27 "github.com/pingcap/tiflow/dm/pkg/terror" 28 "github.com/stretchr/testify/require" 29 ) 30 31 func TestSuite(t *testing.T) { 32 check.TestingT(t) 33 } 34 35 var _ = check.Suite(&testUnitSuite{}) 36 37 type testUnitSuite struct{} 38 39 func (t *testUnitSuite) TestIsCtxCanceledProcessErr(c *check.C) { 40 err := NewProcessError(context.Canceled) 41 c.Assert(IsCtxCanceledProcessErr(err), check.IsTrue) 42 43 err = NewProcessError(errors.New("123")) 44 c.Assert(IsCtxCanceledProcessErr(err), check.IsFalse) 45 46 terr := terror.ErrDBBadConn 47 err = NewProcessError(terror.ErrDBBadConn) 48 c.Assert(err.GetErrCode(), check.Equals, int32(terr.Code())) 49 c.Assert(err.GetErrClass(), check.Equals, terr.Class().String()) 50 c.Assert(err.GetErrLevel(), check.Equals, terr.Level().String()) 51 c.Assert(err.GetMessage(), check.Equals, terr.Message()) 52 c.Assert(err.GetRawCause(), check.Equals, "") 53 } 54 55 func (t *testUnitSuite) TestJoinProcessErrors(c *check.C) { 56 errs := []*pb.ProcessError{ 57 NewProcessError(terror.ErrDBDriverError.Generate()), 58 NewProcessError(terror.ErrSyncUnitDMLStatementFound.Generate()), 59 } 60 61 c.Assert(JoinProcessErrors(errs), check.Equals, 62 `ErrCode:10001 ErrClass:"database" ErrScope:"not-set" ErrLevel:"high" Message:"database driver error" Workaround:"Please check the database connection and the database config in configuration file." , ErrCode:36014 ErrClass:"sync-unit" ErrScope:"internal" ErrLevel:"high" Message:"only support ROW format binlog, unexpected DML statement found in query event" `) 63 } 64 65 func TestIsResumableError(t *testing.T) { 66 testCases := []struct { 67 err error 68 resumable bool 69 }{ 70 // only DM new error is checked 71 {&tmysql.SQLError{Code: 1105, Message: "unsupported modify column length 20 is less than origin 40", State: tmysql.DefaultMySQLState}, true}, 72 {&tmysql.SQLError{Code: 1105, Message: "unsupported drop integer primary key", State: tmysql.DefaultMySQLState}, true}, 73 {&tmysql.SQLError{Code: 1072, Message: "column c id 3 does not exist, this column may have been updated by other DDL ran in parallel", State: tmysql.DefaultMySQLState}, true}, 74 {terror.ErrDBExecuteFailed.Generate("file test.t3.sql: execute statement failed: USE `test_abc`;: context canceled"), true}, 75 {terror.ErrDBExecuteFailed.Delegate(&tmysql.SQLError{Code: 1105, Message: "unsupported modify column length 20 is less than origin 40", State: tmysql.DefaultMySQLState}, "alter table t modify col varchar(20)"), false}, 76 {terror.ErrDBExecuteFailed.Delegate(&tmysql.SQLError{Code: 1105, Message: "unsupported drop integer primary key", State: tmysql.DefaultMySQLState}, "alter table t drop column id"), false}, 77 {terror.ErrDBExecuteFailed.Delegate(&tmysql.SQLError{Code: 1067, Message: "Invalid default value for 'ct'", State: tmysql.DefaultMySQLState}, "CREATE TABLE `tbl` (`c1` int(11) NOT NULL,`ct` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',PRIMARY KEY (`c1`)) ENGINE=InnoDB DEFAULT CHARSET=latin1"), false}, 78 {terror.ErrDBExecuteFailed.Delegate(errors.New("Error 1062 (23000): Duplicate entry '5' for key 'PRIMARY'")), false}, 79 {terror.ErrDBExecuteFailed.Delegate(errors.New("INSERT INTO `db`.`tbl` (`c1`,`c2`) VALUES (?,?);: Error 1406: Data too long for column 'c2' at row 1")), false}, 80 // real error is generated by `Delegate` and multiple `Annotatef`, we use `New` to simplify it 81 {terror.ErrParserParseRelayLog.New("parse relay log file bin.000018 from offset 555 in dir /home/tidb/deploy/relay_log/d2e831df-b4ec-11e9-9237-0242ac110008.000004: parse relay log file bin.000018 from offset 0 in dir /home/tidb/deploy/relay_log/d2e831df-b4ec-11e9-9237-0242ac110008.000004: parse relay log file /home/tidb/deploy/relay_log/d2e831df-b4ec-11e9-9237-0242ac110008.000004/bin.000018: binlog checksum mismatch, data may be corrupted"), false}, 82 {terror.ErrParserParseRelayLog.New("parse relay log file bin.000018 from offset 500 in dir /home/tidb/deploy/relay_log/d2e831df-b4ec-11e9-9237-0242ac110008.000004: parse relay log file bin.000018 from offset 0 in dir /home/tidb/deploy/relay_log/d2e831df-b4ec-11e9-9237-0242ac110008.000004: parse relay log file /home/tidb/deploy/relay_log/d2e831df-b4ec-11e9-9237-0242ac110008.000004/bin.000018: get event err EOF, need 1567488104 but got 316323"), false}, 83 {terror.ErrSyncUnitDDLWrongSequence.Generate("wrong sequence", "right sequence"), false}, 84 {terror.ErrSyncerShardDDLConflict.Generate("conflict DDL", "conflict"), true}, 85 // others 86 {nil, true}, 87 {errors.New("unknown error"), true}, 88 {terror.ErrNotSet.Delegate(&tmysql.SQLError{Code: 1236, Message: "Could not find first log file name in binary log index file", State: tmysql.DefaultMySQLState}), false}, 89 {terror.ErrNotSet.Delegate(&tmysql.SQLError{Code: 1236, Message: "The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires", State: tmysql.DefaultMySQLState}), false}, 90 {terror.ErrLoadLightningRuntime.Delegate(common.ErrDBConnect), false}, 91 } 92 93 for _, tc := range testCases { 94 err := NewProcessError(tc.err) 95 require.Equal(t, tc.resumable, IsResumableError(err)) 96 } 97 } 98 99 func TestIsResumableDBError(t *testing.T) { 100 testCases := []struct { 101 err error 102 resumable bool 103 }{ 104 // only DM new error is checked 105 {&tmysql.SQLError{Code: 1105, Message: "unsupported modify column length 20 is less than origin 40", State: tmysql.DefaultMySQLState}, false}, 106 {&tmysql.SQLError{Code: 1105, Message: "unsupported drop integer primary key", State: tmysql.DefaultMySQLState}, false}, 107 {terror.ErrDBExecuteFailed.Generate("file test.t3.sql: execute statement failed: USE `test_abc`;: context canceled"), true}, 108 {terror.ErrDBExecuteFailed.Delegate(&tmysql.SQLError{Code: 1105, Message: "unsupported modify column length 20 is less than origin 40", State: tmysql.DefaultMySQLState}, "alter table t modify col varchar(20)"), false}, 109 {terror.ErrDBExecuteFailed.Delegate(&tmysql.SQLError{Code: 1105, Message: "unsupported drop integer primary key", State: tmysql.DefaultMySQLState}, "alter table t drop column id"), false}, 110 {terror.ErrDBExecuteFailed.Delegate(&tmysql.SQLError{Code: 1067, Message: "Invalid default value for 'ct'", State: tmysql.DefaultMySQLState}, "CREATE TABLE `tbl` (`c1` int(11) NOT NULL,`ct` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',PRIMARY KEY (`c1`)) ENGINE=InnoDB DEFAULT CHARSET=latin1"), false}, 111 {terror.ErrDBExecuteFailed.Delegate(errors.New("Error 1062 (23000): Duplicate entry '5' for key 'PRIMARY'")), false}, 112 {terror.ErrDBExecuteFailed.Delegate(errors.New("INSERT INTO `db`.`tbl` (`c1`,`c2`) VALUES (?,?);: Error 1406: Data too long for column 'c2' at row 1")), false}, 113 // others 114 {nil, true}, 115 {errors.New("unknown error"), true}, 116 {driver.ErrBadConn, true}, 117 {mysql.ErrInvalidConn, true}, 118 {context.Canceled, false}, 119 } 120 121 for i, tc := range testCases { 122 require.Equal(t, tc.resumable, IsResumableDBError(tc.err), "case %d", i) 123 } 124 } 125 126 func TestIsResumableRelayError(t *testing.T) { 127 testCases := []struct { 128 err error 129 resumable bool 130 }{ 131 {terror.ErrRelayUUIDSuffixNotValid, false}, 132 {terror.ErrRelayUUIDSuffixLessThanPrev, false}, 133 {terror.ErrRelayBinlogNameNotValid, false}, 134 {terror.ErrRelayNoCurrentUUID, false}, 135 {terror.ErrDBBadConn, true}, 136 } 137 138 for _, tc := range testCases { 139 err := NewProcessError(tc.err) 140 require.Equal(t, tc.resumable, IsResumableRelayError(err)) 141 } 142 }