github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/errorutil/util_test.go (about) 1 // Copyright 2021 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 errorutil 15 16 import ( 17 "errors" 18 "testing" 19 20 "github.com/go-sql-driver/mysql" 21 "github.com/pingcap/tidb/pkg/infoschema" 22 tmysql "github.com/pingcap/tidb/pkg/parser/mysql" 23 "github.com/pingcap/tiflow/dm/pkg/terror" 24 "github.com/pingcap/tiflow/engine/framework/model" 25 "github.com/stretchr/testify/require" 26 v3rpc "go.etcd.io/etcd/api/v3/v3rpc/rpctypes" 27 "go.etcd.io/etcd/raft/v3" 28 ) 29 30 func newMysqlErr(number uint16, message string) *mysql.MySQLError { 31 return &mysql.MySQLError{ 32 Number: number, 33 Message: message, 34 } 35 } 36 37 func TestIgnoreMysqlDDLError(t *testing.T) { 38 cases := []struct { 39 err error 40 ret bool 41 }{ 42 {errors.New("raw error"), false}, 43 {newMysqlErr(tmysql.ErrDupKeyName, "Error: Duplicate key name 'some_key'"), true}, 44 {newMysqlErr(uint16(infoschema.ErrDatabaseExists.Code()), "Can't create database"), true}, 45 {newMysqlErr(uint16(infoschema.ErrAccessDenied.Code()), "Access denied for user"), false}, 46 } 47 48 for _, item := range cases { 49 require.Equal(t, item.ret, IsIgnorableMySQLDDLError(item.err)) 50 } 51 } 52 53 func TestIsRetryableEtcdError(t *testing.T) { 54 cases := []struct { 55 err error 56 ret bool 57 }{ 58 {nil, false}, 59 {v3rpc.ErrCorrupt, false}, 60 61 {v3rpc.ErrGRPCTimeoutDueToConnectionLost, true}, 62 {v3rpc.ErrTimeoutDueToLeaderFail, true}, 63 {v3rpc.ErrNoSpace, true}, 64 {raft.ErrStopped, true}, 65 {errors.New("rpc error: code = Unavailable desc = closing transport due to: " + 66 "connection error: desc = \\\"error reading from server: EOF\\\", " + 67 "received prior goaway: code: NO_ERROR\""), true}, 68 {errors.New("rpc error: code = Unavailable desc = error reading from server: " + 69 "xxx: read: connection reset by peer"), true}, 70 } 71 72 for _, item := range cases { 73 require.Equal(t, item.ret, IsRetryableEtcdError(item.err)) 74 } 75 } 76 77 func TestIsRetryableDMLError(t *testing.T) { 78 cases := []struct { 79 err error 80 ret bool 81 }{ 82 {nil, false}, 83 {errors.New("raw error"), false}, 84 {newMysqlErr(tmysql.ErrDupKeyName, "Error: Duplicate key name 'some_key'"), false}, 85 {tmysql.ErrBadConn, true}, 86 {newMysqlErr(tmysql.ErrLockWaitTimeout, "Lock wait timeout exceeded"), false}, 87 {newMysqlErr(tmysql.ErrLockDeadlock, "Deadlock found when trying to get lock"), true}, 88 } 89 90 for _, c := range cases { 91 require.Equal(t, c.ret, IsRetryableDMLError(c.err)) 92 } 93 } 94 95 func TestIsRetryableDDLError(t *testing.T) { 96 cases := []struct { 97 err error 98 ret bool 99 }{ 100 {errors.New("raw error"), false}, 101 {newMysqlErr(tmysql.ErrNoDB, "Error: Duplicate key name 'some_key'"), false}, 102 {newMysqlErr(tmysql.ErrParse, "Can't create database"), false}, 103 {newMysqlErr(tmysql.ErrAccessDenied, "Access denied for user"), false}, 104 {newMysqlErr(tmysql.ErrDBaccessDenied, "Access denied for db"), false}, 105 {newMysqlErr(tmysql.ErrNoSuchTable, "table not exist"), false}, 106 {newMysqlErr(tmysql.ErrNoSuchIndex, "index not exist"), false}, 107 {newMysqlErr(tmysql.ErrWrongColumnName, "wrong column name'"), false}, 108 {newMysqlErr(tmysql.ErrDupKeyName, "Duplicate key name 'some_key'"), true}, 109 {newMysqlErr(tmysql.ErrPartitionMgmtOnNonpartitioned, "xx"), false}, 110 {newMysqlErr(tmysql.ErrNonuniqTable, "xx"), false}, 111 {newMysqlErr(tmysql.ErrBadDB, "xx"), false}, 112 {mysql.ErrInvalidConn, true}, 113 } 114 115 for _, c := range cases { 116 require.Equal(t, c.ret, IsRetryableDDLError(c.err)) 117 } 118 } 119 120 func TestIsSyncPointIgnoreError(t *testing.T) { 121 t.Parallel() 122 cases := []struct { 123 err error 124 ret bool 125 }{ 126 {errors.New("raw error"), false}, 127 {newMysqlErr(tmysql.ErrDupKeyName, "Error: Duplicate key name 'some_key'"), false}, 128 {newMysqlErr(tmysql.ErrNoDB, "Error: Duplicate key name 'some_key'"), false}, 129 {newMysqlErr(tmysql.ErrParse, "Can't create database"), false}, 130 {newMysqlErr(tmysql.ErrUnknownSystemVariable, "Unknown system variable"), true}, 131 } 132 for _, c := range cases { 133 require.Equal(t, c.ret, IsSyncPointIgnoreError(c.err)) 134 } 135 } 136 137 func TestConvertErr(t *testing.T) { 138 normalErr := errors.New("normal error") 139 require.Equal(t, normalErr, ConvertErr(model.DMJobMaster, normalErr)) 140 141 // 11074 codeBinlogEventNoColumns 142 baseDMError, ok := terror.ErrorFromCode(terror.ErrCode(11074)) 143 require.True(t, ok) 144 raw := baseDMError.Generate() 145 err := errors.New(raw.Error()) 146 reflectErr := ConvertErr(model.DMJobMaster, err) 147 require.NotNil(t, reflectErr) 148 require.True(t, baseDMError.Equal(reflectErr)) 149 // convert using other worker type 150 reflectErr2 := ConvertErr(model.WorkerDMDump, err) 151 require.NotNil(t, reflectErr2) 152 require.False(t, baseDMError.Equal(reflectErr2)) 153 require.Equal(t, reflectErr2, err) 154 }