github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/terror/terror_test.go (about)

     1  // Copyright 2019 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 terror
    15  
    16  import (
    17  	"errors"
    18  	"fmt"
    19  	"strings"
    20  	"testing"
    21  
    22  	perrors "github.com/pingcap/errors"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestTError(t *testing.T) {
    27  	t.Parallel()
    28  
    29  	var (
    30  		code                  = codeDBBadConn
    31  		class                 = ClassDatabase
    32  		scope                 = ScopeUpstream
    33  		level                 = LevelMedium
    34  		message               = "bad connection"
    35  		workaround            = "please check your network connection"
    36  		messageArgs           = "message with args: %s"
    37  		commonErr             = errors.New("common error")
    38  		errFormat             = errBaseFormat + ", Message: %s, Workaround: %s"
    39  		errFormatWithArg      = errBaseFormat + ", Message: %s: %s, Workaround: %s"
    40  		errFormatWithRawCause = errBaseFormat + ", Message: %s, RawCause: %s, Workaround: %s"
    41  	)
    42  
    43  	require.Equal(t, errClass2Str[ClassDatabase], ClassDatabase.String())
    44  	require.Equal(t, "unknown error class: 10000", ErrClass(10000).String())
    45  
    46  	require.Equal(t, errScope2Str[ScopeUpstream], ScopeUpstream.String())
    47  	require.Equal(t, "unknown error scope: 10000", ErrScope(10000).String())
    48  
    49  	require.Equal(t, errLevel2Str[LevelHigh], LevelHigh.String())
    50  	require.Equal(t, "unknown error level: 10000", ErrLevel(10000).String())
    51  
    52  	// test Error basic API
    53  	err := New(code, class, scope, level, message, workaround)
    54  	require.Equal(t, code, err.code)
    55  	require.Equal(t, class, err.Class())
    56  	require.Equal(t, scope, err.scope)
    57  	require.Equal(t, level, err.level)
    58  	require.Equal(t, workaround, err.workaround)
    59  	require.Equal(t, fmt.Sprintf(errFormat, code, class, scope, level, err.getMsg(), workaround), err.Error())
    60  
    61  	setMsgErr := err.SetMessage(messageArgs)
    62  	require.Equal(t, messageArgs, setMsgErr.getMsg())
    63  	setMsgErr.args = []interface{}{"1062"}
    64  	require.Equal(t, fmt.Sprintf(messageArgs, setMsgErr.args...), setMsgErr.getMsg())
    65  
    66  	// test Error Generate/Generatef
    67  	err2 := err.Generate("1063")
    68  	require.True(t, err.Equal(err2))
    69  	require.Equal(t, fmt.Sprintf(errFormat, code, class, scope, level, "bad connection%!(EXTRA string=1063)", workaround), err2.Error())
    70  
    71  	err3 := err.Generatef("new message format: %s", "1064")
    72  	require.True(t, err.Equal(err3))
    73  	require.Equal(t, fmt.Sprintf(errFormatWithArg, code, class, scope, level, "new message format", "1064", workaround), err3.Error())
    74  
    75  	// test Error Delegate
    76  	require.Nil(t, err.Delegate(nil, "nil"))
    77  	err4 := err.Delegate(commonErr)
    78  	require.True(t, err.Equal(err4))
    79  	require.Equal(t, fmt.Sprintf(errFormatWithRawCause, code, class, scope, level, message, commonErr, workaround), err4.Error())
    80  	require.Equal(t, commonErr, perrors.Cause(err4))
    81  
    82  	argsErr := New(code, class, scope, level, messageArgs, workaround)
    83  	err4 = argsErr.Delegate(commonErr, "1065")
    84  	require.True(t, argsErr.Equal(err4))
    85  	require.Equal(t, fmt.Sprintf(errFormatWithRawCause, code, class, scope, level, "message with args: 1065", commonErr, workaround), err4.Error())
    86  
    87  	// test Error AnnotateDelegate
    88  	require.Nil(t, err.AnnotateDelegate(nil, "message", "args"))
    89  	err5 := err.AnnotateDelegate(commonErr, "annotate delegate error: %d", 1066)
    90  	require.True(t, err.Equal(err5))
    91  	require.Equal(t, fmt.Sprintf(errFormatWithRawCause, code, class, scope, level, "annotate delegate error: 1066", commonErr, workaround), err5.Error())
    92  
    93  	// test Error Annotate
    94  	oldMsg := err.getMsg()
    95  	err6 := Annotate(err, "annotate error")
    96  	require.True(t, err.Equal(err6))
    97  	require.Equal(t, fmt.Sprintf(errFormatWithArg, code, class, scope, level, "annotate error", oldMsg, workaround), err6.Error())
    98  
    99  	require.Nil(t, Annotate(nil, ""))
   100  	annotateErr := Annotate(commonErr, "annotate")
   101  	_, ok := annotateErr.(*Error)
   102  	require.False(t, ok)
   103  	require.Equal(t, commonErr, perrors.Cause(annotateErr))
   104  
   105  	// test Error Annotatef
   106  	oldMsg = err.getMsg()
   107  	err7 := Annotatef(err, "annotatef error %s", "1067")
   108  	require.True(t, err.Equal(err7))
   109  	require.Equal(t, fmt.Sprintf(errFormatWithArg, code, class, scope, level, "annotatef error 1067", oldMsg, workaround), err7.Error())
   110  
   111  	require.Nil(t, Annotatef(nil, ""))
   112  	annotateErr = Annotatef(commonErr, "annotatef %s", "1068")
   113  	_, ok = annotateErr.(*Error)
   114  	require.False(t, ok)
   115  	require.Equal(t, commonErr, perrors.Cause(annotateErr))
   116  
   117  	// test format
   118  	require.Equal(t, fmt.Sprintf("%q", err.Error()), fmt.Sprintf("%q", err))
   119  	// err has no stack trace
   120  	require.Equal(t, err.Error(), fmt.Sprintf("%+v", err))
   121  	require.Equal(t, err.Error(), fmt.Sprintf("%v", err))
   122  
   123  	// err2 has stack trace
   124  	verbose := strings.Split(fmt.Sprintf("%+v", err2), "\n")
   125  	require.True(t, len(verbose) > 5)
   126  	require.Equal(t, err2.Error(), verbose[0])
   127  	require.Regexp(t, ".*\\(\\*Error\\)\\.Generate", verbose[1])
   128  	require.Equal(t, err2.Error(), fmt.Sprintf("%v", err2))
   129  
   130  	// test Message function
   131  	require.Equal(t, "", Message(nil))
   132  	require.Equal(t, commonErr.Error(), Message(commonErr))
   133  	require.Equal(t, err.getMsg(), Message(err))
   134  }
   135  
   136  func TestTErrorStackTrace(t *testing.T) {
   137  	t.Parallel()
   138  
   139  	err := ErrDBUnExpect
   140  
   141  	testCases := []struct {
   142  		fn               string
   143  		message          string
   144  		args             []interface{}
   145  		stackFingerprint string
   146  	}{
   147  		{"new", "new error", nil, ".*\\(\\*Error\\)\\.New"},
   148  		{"generate", "", []interface{}{"parma1"}, ".*\\(\\*Error\\)\\.Generate"},
   149  		{"generatef", "generatef error %s %d", []interface{}{"param1", 12}, ".*\\(\\*Error\\)\\.Generatef"},
   150  	}
   151  
   152  	for _, tc := range testCases {
   153  		var err2 error
   154  		switch tc.fn {
   155  		case "new":
   156  			err2 = err.New(tc.message)
   157  		case "generate":
   158  			err2 = err.Generate(tc.args...)
   159  		case "generatef":
   160  			err2 = err.Generatef(tc.message, tc.args...)
   161  		}
   162  		verbose := strings.Split(fmt.Sprintf("%+v", err2), "\n")
   163  		require.True(t, len(verbose) > 5)
   164  		require.Equal(t, err2.Error(), verbose[0])
   165  		require.Regexp(t, tc.stackFingerprint, verbose[1])
   166  	}
   167  }
   168  
   169  func TestTerrorWithOperate(t *testing.T) {
   170  	t.Parallel()
   171  
   172  	var (
   173  		code             = codeDBBadConn
   174  		class            = ClassDatabase
   175  		scope            = ScopeUpstream
   176  		level            = LevelMedium
   177  		message          = "message with args: %s"
   178  		workaround       = "please check your connection"
   179  		err              = New(code, class, scope, level, message, workaround)
   180  		arg              = "arg"
   181  		commonErr        = perrors.New("common error")
   182  		errFormatWithArg = errBaseFormat + ", Message: %s: %s, Workaround: %s"
   183  	)
   184  
   185  	// test WithScope
   186  	newScope := ScopeDownstream
   187  	require.Nil(t, WithScope(nil, newScope))
   188  	require.Equal(t, fmt.Sprintf("error scope: %s: common error", newScope), WithScope(commonErr, newScope).Error())
   189  	err1 := WithScope(err.Generate(arg), newScope)
   190  	require.True(t, err.Equal(err1))
   191  	require.Equal(t, fmt.Sprintf(errFormatWithArg, code, class, newScope, level, "message with args", arg, workaround), err1.Error())
   192  
   193  	// test WithClass
   194  	newClass := ClassFunctional
   195  	require.Nil(t, WithClass(nil, newClass))
   196  	require.Equal(t, fmt.Sprintf("error class: %s: common error", newClass), WithClass(commonErr, newClass).Error())
   197  	err2 := WithClass(err.Generate(arg), newClass)
   198  	require.True(t, err.Equal(err2))
   199  	require.Equal(t, fmt.Sprintf(errFormatWithArg, code, newClass, scope, level, "message with args", arg, workaround), err2.Error())
   200  }
   201  
   202  func TestTerrorCodeMap(t *testing.T) {
   203  	t.Parallel()
   204  
   205  	err, ok := ErrorFromCode(codeDBDriverError)
   206  	require.True(t, ok)
   207  	require.True(t, ErrDBDriverError.Equal(err))
   208  
   209  	_, ok = ErrorFromCode(1000)
   210  	require.False(t, ok)
   211  }