github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/errors/helper_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 errors 15 16 import ( 17 "context" 18 "fmt" 19 "net/http" 20 "testing" 21 22 "github.com/pingcap/errors" 23 "github.com/stretchr/testify/require" 24 "google.golang.org/grpc/codes" 25 ) 26 27 func TestWrapError(t *testing.T) { 28 t.Parallel() 29 var ( 30 err = errors.New("cause error") 31 testCases = []struct { 32 rfcError *errors.Error 33 err error 34 isNil bool 35 expected string 36 args []interface{} 37 }{ 38 {ErrDecodeFailed, nil, true, "", nil}, 39 { 40 ErrDecodeFailed, err, false, 41 "[CDC:ErrDecodeFailed]decode failed: args data: cause error", 42 []interface{}{"args data"}, 43 }, 44 } 45 ) 46 for _, tc := range testCases { 47 we := WrapError(tc.rfcError, tc.err, tc.args...) 48 if tc.isNil { 49 require.Nil(t, we) 50 } else { 51 require.NotNil(t, we) 52 require.Equal(t, we.Error(), tc.expected) 53 } 54 } 55 } 56 57 func TestRFCCode(t *testing.T) { 58 t.Parallel() 59 rfc, ok := RFCCode(ErrAPIInvalidParam) 60 require.Equal(t, true, ok) 61 require.Contains(t, rfc, "ErrAPIInvalidParam") 62 63 err := fmt.Errorf("inner error: invalid request") 64 rfc, ok = RFCCode(err) 65 require.Equal(t, false, ok) 66 require.Equal(t, rfc, errors.RFCErrorCode("")) 67 68 rfcErr := ErrAPIInvalidParam 69 Err := WrapError(rfcErr, err) 70 rfc, ok = RFCCode(Err) 71 require.Equal(t, true, ok) 72 require.Contains(t, rfc, "ErrAPIInvalidParam") 73 74 anoErr := errors.Annotate(ErrEtcdTryAgain, "annotated Etcd Try again") 75 rfc, ok = RFCCode(anoErr) 76 require.Equal(t, true, ok) 77 require.Contains(t, rfc, "ErrEtcdTryAgain") 78 } 79 80 func TestIsRetryableError(t *testing.T) { 81 t.Parallel() 82 tests := []struct { 83 name string 84 err error 85 want bool 86 }{ 87 {"nil error", nil, false}, 88 {"context Canceled err", context.Canceled, false}, 89 {"context DeadlineExceeded err", context.DeadlineExceeded, false}, 90 {"normal err", errors.New("test"), true}, 91 {"cdc reachMaxTry err", ErrReachMaxTry, true}, 92 } 93 for _, tt := range tests { 94 ret := IsRetryableError(tt.err) 95 require.Equal(t, ret, tt.want, "case:%s", tt.name) 96 } 97 } 98 99 func TestChangefeedFastFailError(t *testing.T) { 100 t.Parallel() 101 err := ErrSnapshotLostByGC.FastGenByArgs() 102 rfcCode, _ := RFCCode(err) 103 require.Equal(t, true, IsChangefeedGCFastFailError(err)) 104 require.Equal(t, true, IsChangefeedGCFastFailErrorCode(rfcCode)) 105 106 err = ErrStartTsBeforeGC.FastGenByArgs() 107 rfcCode, _ = RFCCode(err) 108 require.Equal(t, true, IsChangefeedGCFastFailError(err)) 109 require.Equal(t, true, IsChangefeedGCFastFailErrorCode(rfcCode)) 110 111 err = ErrToTLSConfigFailed.FastGenByArgs() 112 rfcCode, _ = RFCCode(err) 113 require.Equal(t, false, IsChangefeedGCFastFailError(err)) 114 require.Equal(t, false, IsChangefeedGCFastFailErrorCode(rfcCode)) 115 } 116 117 func TestShouldFailChangefeed(t *testing.T) { 118 t.Parallel() 119 cases := []struct { 120 err error 121 expected bool 122 }{ 123 { 124 err: ErrInvalidIgnoreEventType.FastGenByArgs(), 125 expected: false, 126 }, 127 { 128 err: ErrExpressionColumnNotFound.FastGenByArgs(), 129 expected: true, 130 }, 131 { 132 err: ErrExpressionParseFailed.FastGenByArgs(), 133 expected: true, 134 }, 135 { 136 err: WrapError(ErrFilterRuleInvalid, ErrExpressionColumnNotFound.FastGenByArgs()), 137 expected: true, 138 }, 139 { 140 err: errors.New("CDC:ErrExpressionColumnNotFound"), 141 expected: true, 142 }, 143 { 144 err: ErrSyncRenameTableFailed.FastGenByArgs(), 145 expected: true, 146 }, 147 { 148 err: WrapChangefeedUnretryableErr(errors.New("whatever")), 149 expected: true, 150 }, 151 { 152 err: WrapError(ErrSinkURIInvalid, errors.New("test")), 153 expected: true, 154 }, 155 { 156 err: WrapError(ErrKafkaInvalidConfig, errors.New("test")), 157 expected: true, 158 }, 159 { 160 err: WrapError(ErrMySQLInvalidConfig, errors.New("test")), 161 expected: true, 162 }, 163 { 164 err: WrapError(ErrStorageSinkInvalidConfig, errors.New("test")), 165 expected: true, 166 }, 167 { 168 err: errors.Trace(WrapError(ErrStorageSinkInvalidConfig, errors.New("test"))), 169 expected: true, 170 }, 171 } 172 173 for _, c := range cases { 174 require.Equal(t, c.expected, ShouldFailChangefeed(c.err)) 175 } 176 177 var code errors.RFCErrorCode 178 var ok bool 179 code, ok = RFCCode(ErrChangefeedUnretryable) 180 require.True(t, ok) 181 require.True(t, ShouldFailChangefeed(errors.New(string(code)))) 182 } 183 184 func TestIsCliUnprintableError(t *testing.T) { 185 t.Parallel() 186 tests := []struct { 187 name string 188 err error 189 want bool 190 }{ 191 {"nil error", nil, false}, 192 {"context Canceled err", context.Canceled, false}, 193 {"context DeadlineExceeded err", context.DeadlineExceeded, false}, 194 {"normal err", errors.New("test"), false}, 195 {"cdc reachMaxTry err", ErrReachMaxTry, false}, 196 {"cli unprint err", ErrCliAborted, true}, 197 } 198 for _, tt := range tests { 199 ret := IsCliUnprintableError(tt.err) 200 require.Equal(t, ret, tt.want, "case:%s", tt.name) 201 } 202 } 203 204 func TestHTTPStatusCode(t *testing.T) { 205 require.Equal(t, http.StatusOK, HTTPStatusCode(nil)) 206 require.Equal(t, 499, HTTPStatusCode(context.Canceled)) 207 require.Equal(t, http.StatusGatewayTimeout, HTTPStatusCode(context.DeadlineExceeded)) 208 require.Equal(t, http.StatusInternalServerError, HTTPStatusCode(errors.New("unknown error"))) 209 for rfcCode, httpCode := range httpStatusCodeMapping { 210 err := errors.Normalize(string(rfcCode), errors.RFCCodeText(string(rfcCode))) 211 require.Equal(t, httpCode, HTTPStatusCode(err)) 212 } 213 } 214 215 func TestGRPCStatusCode(t *testing.T) { 216 require.Equal(t, codes.OK, GRPCStatusCode(nil)) 217 require.Equal(t, codes.Canceled, GRPCStatusCode(context.Canceled)) 218 require.Equal(t, codes.DeadlineExceeded, GRPCStatusCode(context.DeadlineExceeded)) 219 require.Equal(t, codes.Unknown, GRPCStatusCode(errors.New("unknown error"))) 220 require.Equal(t, codes.Internal, GRPCStatusCode(errors.Normalize("internal error", errors.RFCCodeText("TEST:ErrInternal")))) 221 for rfcCode, gRPCCode := range gRPCStatusCodeMapping { 222 err := errors.Normalize(string(rfcCode), errors.RFCCodeText(string(rfcCode))) 223 require.Equal(t, gRPCCode, GRPCStatusCode(err)) 224 } 225 }