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  }