trpc.group/trpc-go/trpc-go@v1.0.3/errs/errs_test.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package errs_test 15 16 import ( 17 "bufio" 18 "bytes" 19 "errors" 20 "fmt" 21 "os" 22 "strings" 23 "testing" 24 25 "github.com/stretchr/testify/assert" 26 "github.com/stretchr/testify/require" 27 "trpc.group/trpc/trpc-protocol/pb/go/trpc" 28 29 "trpc.group/trpc-go/trpc-go/errs" 30 ) 31 32 // go test -v -coverprofile=cover.out 33 // go tool cover -func=cover.out 34 35 func TestErrs(t *testing.T) { 36 var err *errs.Error 37 str := err.Error() 38 assert.Contains(t, str, "success") 39 40 e := errs.New(111, "inner fail") 41 assert.NotNil(t, e) 42 43 assert.EqualValues(t, 111, errs.Code(e)) 44 assert.Equal(t, "inner fail", errs.Msg(e)) 45 46 err, ok := e.(*errs.Error) 47 assert.Equal(t, true, ok) 48 assert.NotNil(t, err) 49 assert.Equal(t, errs.ErrorTypeBusiness, err.Type) 50 51 str = err.Error() 52 assert.Contains(t, str, "business") 53 54 e = errs.NewFrameError(111, "inner fail") 55 assert.NotNil(t, e) 56 57 assert.EqualValues(t, 111, errs.Code(e)) 58 assert.Equal(t, "inner fail", errs.Msg(e)) 59 60 err, ok = e.(*errs.Error) 61 assert.Equal(t, true, ok) 62 assert.NotNil(t, err) 63 assert.Equal(t, errs.ErrorTypeFramework, err.Type) 64 65 str = err.Error() 66 assert.Contains(t, str, "framework") 67 68 assert.EqualValues(t, 0, errs.Code(nil)) 69 assert.Equal(t, "success", errs.Msg(nil)) 70 71 assert.EqualValues(t, 0, errs.Code((*errs.Error)(nil))) 72 assert.Equal(t, "success", errs.Msg((*errs.Error)(nil))) 73 74 e = errors.New("unknown error") 75 assert.Equal(t, errs.RetUnknown, errs.Code(e)) 76 assert.Equal(t, "unknown error", errs.Msg(e)) 77 78 err.Type = errs.ErrorTypeCalleeFramework 79 assert.Contains(t, err.Error(), "type:callee framework") 80 } 81 82 func TestNonEmptyStringOnEmptyMsg(t *testing.T) { 83 e := errs.New(errs.RetServerSystemErr, "") 84 require.Contains(t, e.Error(), "code:") 85 require.Contains(t, e.Error(), "type:") 86 } 87 88 func TestErrsFormat(t *testing.T) { 89 err := errs.New(10000, "test error") 90 91 s := fmt.Sprintf("%s", err) 92 assert.Equal(t, "type:business, code:10000, msg:test error", s) 93 94 s = fmt.Sprintf("%q", err) 95 assert.Equal(t, `"type:business, code:10000, msg:test error"`, s) 96 97 s = fmt.Sprintf("%v", err) 98 assert.Equal(t, "type:business, code:10000, msg:test error", s) 99 100 s = fmt.Sprintf("%d", err) 101 assert.Equal(t, "%!d(errs.Error=type:business, code:10000, msg:test error)", s) 102 } 103 104 func TestNewFrameError(t *testing.T) { 105 ok := true 106 errs.SetTraceable(ok) 107 e := errs.NewFrameError(111, "inner fail") 108 assert.NotNil(t, e) 109 } 110 111 func TestWrapFrameError(t *testing.T) { 112 ok := true 113 errs.SetTraceable(ok) 114 e := errs.WrapFrameError(errs.New(123, "inner fail"), 456, "wrap frame error") 115 assert.NotNil(t, e) 116 e = errs.WrapFrameError(nil, 456, "wrap frame error") 117 assert.Nil(t, e) 118 } 119 120 func TestTraceError(t *testing.T) { 121 122 errs.SetTraceable(true) 123 124 err := parent() 125 assert.NotNil(t, err) 126 127 s := fmt.Sprintf("%+v", err) 128 br := bufio.NewReader(strings.NewReader(s)) 129 130 line, isPrefix, err := br.ReadLine() 131 assert.Equal(t, "type:business, code:111, msg:inner fail", string(line)) 132 assert.Equal(t, isPrefix, false) 133 assert.Nil(t, err) 134 135 line, isPrefix, err = br.ReadLine() 136 assert.Equal(t, "trpc.group/trpc-go/trpc-go/errs_test.grandson", string(line)) 137 assert.Equal(t, isPrefix, false) 138 assert.Nil(t, err) 139 140 _, _, _ = br.ReadLine() 141 line, isPrefix, err = br.ReadLine() 142 assert.Equal(t, "trpc.group/trpc-go/trpc-go/errs_test.child", string(line)) 143 assert.Equal(t, isPrefix, false) 144 assert.Nil(t, err) 145 146 _, _, _ = br.ReadLine() 147 line, isPrefix, err = br.ReadLine() 148 assert.Equal(t, "trpc.group/trpc-go/trpc-go/errs_test.parent", string(line)) 149 assert.Equal(t, isPrefix, false) 150 assert.Nil(t, err) 151 } 152 153 func TestTraceErrorSetStackSkip(t *testing.T) { 154 errs.SetTraceable(true) 155 errs.SetStackSkip(4) 156 157 err := func() error { 158 return func() error { 159 return newMyErr(11, "TestTraceErrorSetStackSkip error") 160 }() 161 }() 162 assert.NotNil(t, err) 163 164 s := fmt.Sprintf("%+v", err) 165 br := bufio.NewReader(strings.NewReader(s)) 166 167 line, isPrefix, err := br.ReadLine() 168 assert.Equal(t, "type:business, code:11, msg:TestTraceErrorSetStackSkip error", string(line)) 169 assert.Equal(t, isPrefix, false) 170 assert.Nil(t, err) 171 172 line, isPrefix, err = br.ReadLine() 173 t.Log(string(line)) 174 assert.Contains(t, string(line), "trpc.group/trpc-go/trpc-go/errs_test.TestTraceErrorSetStackSkip") 175 assert.Equal(t, isPrefix, false) 176 assert.Nil(t, err) 177 178 _, _, _ = br.ReadLine() 179 line, isPrefix, err = br.ReadLine() 180 assert.Equal(t, "trpc.group/trpc-go/trpc-go/errs_test.TestTraceErrorSetStackSkip.func1", string(line)) 181 assert.Equal(t, isPrefix, false) 182 assert.Nil(t, err) 183 184 _, _, _ = br.ReadLine() 185 line, isPrefix, err = br.ReadLine() 186 assert.Equal(t, "trpc.group/trpc-go/trpc-go/errs_test.TestTraceErrorSetStackSkip", string(line)) 187 assert.Equal(t, isPrefix, false) 188 assert.Nil(t, err) 189 } 190 191 func newMyErr(code int, msg string) error { 192 return errs.New(code, msg) 193 } 194 195 // TestSetTraceableWithContent SetTraceableWithContent interface test case, 196 // filter and print stack information according to Content. 197 func TestSetTraceableWithContent(t *testing.T) { 198 errs.SetTraceableWithContent("child") 199 200 err := parent() 201 assert.NotNil(t, err) 202 203 s := fmt.Sprintf("%+v", err) 204 br := bufio.NewReader(strings.NewReader(s)) 205 line, isPrefix, err := br.ReadLine() 206 assert.Equal(t, "type:business, code:111, msg:inner fail", string(line)) 207 assert.Equal(t, isPrefix, false) 208 assert.Nil(t, err) 209 210 line, isPrefix, err = br.ReadLine() 211 assert.Equal(t, "trpc.group/trpc-go/trpc-go/errs_test.child", string(line)) 212 assert.Equal(t, isPrefix, false) 213 assert.Nil(t, err) 214 } 215 216 func TestErrorChain(t *testing.T) { 217 var e error = errs.Wrap(os.ErrDeadlineExceeded, int(trpc.TrpcRetCode_TRPC_CLIENT_INVOKE_TIMEOUT_ERR), "just wrap") 218 require.Contains(t, errs.Msg(e), os.ErrDeadlineExceeded.Error()) 219 e = fmt.Errorf("%w", e) 220 require.Equal(t, trpc.TrpcRetCode_TRPC_CLIENT_INVOKE_TIMEOUT_ERR, errs.Code(e)) 221 require.True(t, errors.Is(e, os.ErrDeadlineExceeded)) 222 require.Contains(t, e.Error(), os.ErrDeadlineExceeded.Error()) 223 } 224 225 func TestWrap(t *testing.T) { 226 err := parent() 227 assert.NotNil(t, err) 228 229 err = errs.Wrap(err, 222, "wrap err") 230 assert.NotNil(t, err) 231 232 s := fmt.Sprintf("%v", err) 233 assert.Contains(t, s, "type:business, code:222, msg:wrap err") 234 s = fmt.Sprintf("%s", err) 235 assert.Contains(t, s, "type:business, code:222, msg:wrap err") 236 237 s = fmt.Sprintf("%+v", err) 238 br := bufio.NewReader(strings.NewReader(s)) 239 line, isPrefix, err := br.ReadLine() 240 assert.Equal(t, "type:business, code:222, msg:wrap err", string(line)) 241 assert.Equal(t, isPrefix, false) 242 assert.Nil(t, err) 243 244 line, isPrefix, err = br.ReadLine() 245 assert.Equal(t, "Cause by type:business, code:111, msg:inner fail", string(line)) 246 assert.Equal(t, isPrefix, false) 247 assert.Nil(t, err) 248 } 249 250 func TestWrapf(t *testing.T) { 251 err := parent() 252 assert.NotNil(t, err) 253 254 err = errs.Wrapf(err, 222, "wrap %v", "err") 255 assert.NotNil(t, err) 256 257 s := fmt.Sprintf("%+v", err) 258 br := bufio.NewReader(strings.NewReader(s)) 259 line, isPrefix, err := br.ReadLine() 260 assert.Equal(t, "type:business, code:222, msg:wrap err", string(line)) 261 assert.Equal(t, isPrefix, false) 262 assert.Nil(t, err) 263 264 line, isPrefix, err = br.ReadLine() 265 assert.Equal(t, "Cause by type:business, code:111, msg:inner fail", string(line)) 266 assert.Equal(t, isPrefix, false) 267 assert.Nil(t, err) 268 } 269 270 func TestWrapSetTraceable(t *testing.T) { 271 // reset 272 errs.SetStackSkip(3) 273 errs.SetTraceableWithContent("") 274 275 err := parent() 276 assert.NotNil(t, err) 277 278 err = errs.Wrap(err, 222, "wrap err") 279 assert.NotNil(t, err) 280 281 s := fmt.Sprintf("%+v", err) 282 br := bufio.NewReader(strings.NewReader(s)) 283 line, isPrefix, err := br.ReadLine() 284 assert.Equal(t, "type:business, code:222, msg:wrap err", string(line)) 285 assert.Equal(t, isPrefix, false) 286 assert.Nil(t, err) 287 288 line, isPrefix, err = br.ReadLine() 289 assert.Equal(t, "Cause by type:business, code:111, msg:inner fail", string(line)) 290 assert.Equal(t, isPrefix, false) 291 assert.Nil(t, err) 292 293 line, isPrefix, err = br.ReadLine() 294 assert.Equal(t, "trpc.group/trpc-go/trpc-go/errs_test.grandson", string(line)) 295 assert.Equal(t, isPrefix, false) 296 assert.Nil(t, err) 297 } 298 299 func TestIsTimeout(t *testing.T) { 300 require.True(t, (&errs.Error{ 301 Type: errs.ErrorTypeFramework, 302 Code: trpc.TrpcRetCode_TRPC_CLIENT_INVOKE_TIMEOUT_ERR, 303 }).IsTimeout(errs.ErrorTypeFramework)) 304 require.True(t, (&errs.Error{ 305 Type: errs.ErrorTypeCalleeFramework, 306 Code: trpc.TrpcRetCode_TRPC_CLIENT_INVOKE_TIMEOUT_ERR, 307 }).IsTimeout(errs.ErrorTypeCalleeFramework)) 308 require.False(t, (&errs.Error{ 309 Type: errs.ErrorTypeBusiness, 310 Code: trpc.TrpcRetCode_TRPC_CLIENT_INVOKE_TIMEOUT_ERR, 311 }).IsTimeout(errs.ErrorTypeFramework)) 312 require.True(t, (&errs.Error{ 313 Type: errs.ErrorTypeFramework, 314 Code: trpc.TrpcRetCode_TRPC_CLIENT_FULL_LINK_TIMEOUT_ERR, 315 }).IsTimeout(errs.ErrorTypeFramework)) 316 require.True(t, (&errs.Error{ 317 Type: errs.ErrorTypeFramework, 318 Code: trpc.TrpcRetCode_TRPC_SERVER_TIMEOUT_ERR, 319 }).IsTimeout(errs.ErrorTypeFramework)) 320 require.True(t, (&errs.Error{ 321 Type: errs.ErrorTypeFramework, 322 Code: trpc.TrpcRetCode_TRPC_SERVER_FULL_LINK_TIMEOUT_ERR, 323 }).IsTimeout(errs.ErrorTypeFramework)) 324 require.False(t, (&errs.Error{ 325 Type: errs.ErrorTypeFramework, 326 Code: errs.RetServerNoService, 327 }).IsTimeout(errs.ErrorTypeFramework)) 328 } 329 330 func TestErrorFormatPrint(t *testing.T) { 331 errs.SetTraceable(false) 332 defer errs.SetTraceable(true) 333 err := errs.New(errs.ErrorTypeFramework, "") 334 var buf bytes.Buffer 335 fmt.Fprintf(&buf, "%+v", err) 336 require.Equal(t, "type:business, code:1, msg:", buf.String()) 337 } 338 339 func TestNestErrors(t *testing.T) { 340 errs.SetTraceable(false) 341 defer errs.SetTraceable(true) 342 const ( 343 code trpc.TrpcRetCode = 101 344 msg = "test error" 345 ) 346 require.Equal(t, code, errs.Code(&testError{Err: errs.New(code, msg)})) 347 require.Equal(t, msg, errs.Msg(&testError{Err: errs.New(code, msg)})) 348 } 349 350 type testError struct { 351 Err error 352 } 353 354 func (te *testError) Error() string { 355 return te.Err.Error() 356 } 357 358 func (te *testError) Unwrap() error { 359 return te.Err 360 } 361 362 //go:noinline 363 func parent() error { 364 if err := child(); err != nil { 365 return err 366 } 367 return nil 368 } 369 370 //go:noinline 371 func child() error { 372 if err := grandson(); err != nil { 373 return err 374 } 375 return nil 376 } 377 378 //go:noinline 379 func grandson() error { 380 return errs.Newf(111, "%s", "inner fail") 381 }