Merge pull request #11599 from wy65701436/revise-base-error

update internal error output format
This commit is contained in:
Wenkai Yin(尹文开) 2020-04-13 20:07:05 +08:00 committed by GitHub
commit 4b4091b217
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 197 additions and 42 deletions

View File

@ -27,40 +27,50 @@ const (
// NotFoundError is error for the case of object not found // NotFoundError is error for the case of object not found
func NotFoundError(err error) *Error { func NotFoundError(err error) *Error {
return New(err).WithCode(NotFoundCode).WithMessage("resource not found") return New("resource not found").WithCode(NotFoundCode).WithCause(err)
} }
// ConflictError is error for the case of object conflict // ConflictError is error for the case of object conflict
func ConflictError(err error) *Error { func ConflictError(err error) *Error {
return New(err).WithCode(ConflictCode).WithMessage("resource conflict") return New("resource conflict").WithCode(ConflictCode).WithCause(err)
} }
// DeniedError is error for the case of denied // DeniedError is error for the case of denied
func DeniedError(err error) *Error { func DeniedError(err error) *Error {
return New(err).WithCode(DENIED).WithMessage("denied") return New("denied").WithCode(DENIED).WithCause(err)
} }
// UnauthorizedError is error for the case of unauthorized accessing // UnauthorizedError is error for the case of unauthorized accessing
func UnauthorizedError(err error) *Error { func UnauthorizedError(err error) *Error {
return New(err).WithCode(UnAuthorizedCode).WithMessage("unauthorized") return New("unauthorized").WithCode(UnAuthorizedCode).WithCause(err)
} }
// BadRequestError is error for the case of bad request // BadRequestError is error for the case of bad request
func BadRequestError(err error) *Error { func BadRequestError(err error) *Error {
return New(err).WithCode(BadRequestCode).WithMessage("bad request") return New("bad request").WithCode(BadRequestCode).WithCause(err)
} }
// ForbiddenError is error for the case of forbidden // ForbiddenError is error for the case of forbidden
func ForbiddenError(err error) *Error { func ForbiddenError(err error) *Error {
return New(err).WithCode(ForbiddenCode).WithMessage("forbidden") return New("forbidden").WithCode(ForbiddenCode).WithCause(err)
} }
// PreconditionFailedError is error for the case of precondition failed // PreconditionFailedError is error for the case of precondition failed
func PreconditionFailedError(err error) *Error { func PreconditionFailedError(err error) *Error {
return New(err).WithCode(PreconditionCode).WithMessage("precondition failed") return New("precondition failed").WithCode(PreconditionCode).WithCause(err)
} }
// UnknownError ... // UnknownError ...
func UnknownError(err error) *Error { func UnknownError(err error) *Error {
return New(err).WithCode(GeneralCode).WithMessage("unknown") return New("unknown").WithCode(GeneralCode).WithCause(err)
}
// IsNotFoundErr returns true when the error is NotFoundError
func IsNotFoundErr(err error) bool {
return IsErr(err, NotFoundCode)
}
// IsConflictErr checks whether the err chain contains conflict error
func IsConflictErr(err error) bool {
return IsErr(err, ConflictCode)
} }

View File

@ -18,8 +18,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"strings"
"github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/log"
) )
@ -39,24 +37,13 @@ type Error struct {
} }
// Error returns a human readable error, error.Error() will not contains the track information. Needs it? just call error.StackTrace() // Error returns a human readable error, error.Error() will not contains the track information. Needs it? just call error.StackTrace()
// Code will not be in the error output.
func (e *Error) Error() string { func (e *Error) Error() string {
var parts []string out := e.Message
var causeStr string
if e.Cause != nil { if e.Cause != nil {
causeStr = e.Cause.Error() out = out + ": " + e.Cause.Error()
parts = append(parts, causeStr)
} }
return out
if e.Code != "" {
parts = append(parts, e.Code)
}
if e.Message != causeStr {
parts = append(parts, e.Message)
}
return strings.Join(parts, ", ")
} }
// StackTrace ... // StackTrace ...
@ -137,8 +124,8 @@ func New(in interface{}) *Error {
default: default:
err = fmt.Errorf("%v", in) err = fmt.Errorf("%v", in)
} }
return &Error{ return &Error{
Cause: err,
Message: err.Error(), Message: err.Error(),
Stack: newStack(), Stack: newStack(),
} }
@ -163,16 +150,18 @@ func Wrapf(err error, format string, args ...interface{}) *Error {
return nil return nil
} }
e := &Error{ e := &Error{
Cause: err, Cause: err,
Stack: newStack(), Message: fmt.Sprintf(format, args...),
Stack: newStack(),
} }
return e.WithMessage(format, args...) return e
} }
// Errorf ... // Errorf ...
func Errorf(format string, args ...interface{}) *Error { func Errorf(format string, args ...interface{}) *Error {
return &Error{ return &Error{
Message: fmt.Sprintf(format, args...), Message: fmt.Sprintf(format, args...),
Stack: newStack(),
} }
} }
@ -183,6 +172,9 @@ func Cause(err error) error {
if !ok { if !ok {
break break
} }
if cause.Cause == nil {
break
}
err = cause.Cause err = cause.Cause
} }
return err return err
@ -191,22 +183,12 @@ func Cause(err error) error {
// IsErr checks whether the err chain contains error matches the code // IsErr checks whether the err chain contains error matches the code
func IsErr(err error, code string) bool { func IsErr(err error, code string) bool {
var e *Error var e *Error
if errors.As(err, &e) { if As(err, &e) {
return e.Code == code return e.Code == code
} }
return false return false
} }
// IsNotFoundErr returns true when the error is NotFoundError
func IsNotFoundErr(err error) bool {
return IsErr(err, NotFoundCode)
}
// IsConflictErr checks whether the err chain contains conflict error
func IsConflictErr(err error) bool {
return IsErr(err, ConflictCode)
}
// ErrCode returns code of err // ErrCode returns code of err
func ErrCode(err error) string { func ErrCode(err error) string {
if err == nil { if err == nil {
@ -214,7 +196,7 @@ func ErrCode(err error) string {
} }
var e *Error var e *Error
if ok := errors.As(err, &e); ok && e.Code != "" { if ok := As(err, &e); ok && e.Code != "" {
return e.Code return e.Code
} else if ok && e.Cause != nil { } else if ok && e.Cause != nil {
return ErrCode(e.Cause) return ErrCode(e.Cause)

View File

@ -62,7 +62,7 @@ func caller2() error {
func caller3() error { func caller3() error {
err := caller4() err := caller4()
return New(err).WithMessage("it's caller 3.") return New(nil).WithMessage("it's caller 3.").WithCause(err)
} }
func caller4() error { func caller4() error {
@ -89,6 +89,169 @@ func (suite *ErrorTestSuite) TestStackTrace() {
suite.Contains(err.Error(), "it's caller 4") suite.Contains(err.Error(), "it's caller 4")
} }
func (suite *ErrorTestSuite) TestNew() {
cause := New("root")
suite.Equal("root", cause.Error())
err := New(cause)
suite.Equal("root", err.Error())
err = New(cause.WithCause(errors.New("stdErr")))
suite.Equal("root: stdErr", err.Error())
errStd := errors.New("stdErr")
err = New(errStd)
suite.Equal("stdErr", err.Error())
err = New(nil)
suite.Equal("<nil>", err.Error())
err = New("")
suite.Equal("", err.Error())
}
func (suite *ErrorTestSuite) TestWithMessage() {
cause := New("root")
err := cause.WithMessage("append message").WithMessage("append message2")
suite.Equal("append message2", err.Error())
}
func (suite *ErrorTestSuite) TestWithCause() {
cause := errors.New("stdErr")
err := New("root").WithCause(cause)
suite.Equal("root: stdErr", err.Error())
}
func (suite *ErrorTestSuite) TestWithCauseMessage() {
cause := errors.New("stdErr")
err := New("root").WithCause(cause).WithMessage("With Message")
suite.Equal("With Message: stdErr", err.Error())
}
func (suite *ErrorTestSuite) TestWrap() {
cause := New("root")
cause = Wrap(cause, "err1")
cause = Wrap(cause, "err2")
cause = Wrap(cause, "err3")
suite.Equal("err3: err2: err1: root", cause.Error())
}
func (suite *ErrorTestSuite) TestWrapf() {
cause := New("root")
cause = Wrapf(cause, "err%d", 1)
cause = Wrapf(cause, "err%d", 2)
cause = Wrapf(cause, "err%d", 3)
suite.Equal("err3: err2: err1: root", cause.Error())
}
func (suite *ErrorTestSuite) TestErrof() {
err := Errorf("it's err%d", 1)
suite.Equal("it's err1", err.Error())
}
func (suite *ErrorTestSuite) TestErrofWithMessage() {
err := Errorf("it's err%d", 1)
suite.Equal("it's err1", err.Error())
}
func (suite *ErrorTestSuite) TestWrapStdErr() {
cause := errors.New("stdErr")
err := Wrap(cause, "wrap stdErr")
suite.Equal("wrap stdErr: stdErr", err.Error())
}
func (suite *ErrorTestSuite) TestNilErr() {
nilErr := New(nil)
suite.Equal("<nil>", nilErr.Error())
}
func (suite *ErrorTestSuite) TestNilWithMessage() {
nilErr := New(nil).WithMessage("it's a nil error")
suite.Equal("it's a nil error", nilErr.Error())
}
func (suite *ErrorTestSuite) TestIsNotFoundErr() {
err := New(nil).WithCode(NotFoundCode)
suite.True(IsNotFoundErr(err))
err = New(nil).WithCode(PreconditionCode)
suite.False(IsNotFoundErr(err))
}
func (suite *ErrorTestSuite) TestIsConflictErrErr() {
err := New(nil).WithCode(ConflictCode)
suite.True(IsConflictErr(err))
err = New(nil).WithCode(PreconditionCode)
suite.False(IsConflictErr(err))
}
func (suite *ErrorTestSuite) TestErrCode() {
err := New(nil).WithCode(ConflictCode)
suite.Equal(ErrCode(err), ConflictCode)
err = New("root")
suite.Equal(ErrCode(err), GeneralCode)
err = New("root")
suite.Equal(ErrCode(err), GeneralCode)
err.WithCode(PreconditionCode)
suite.Equal(ErrCode(err), PreconditionCode)
err.WithCode(DENIED)
suite.Equal(ErrCode(err), DENIED)
stdErr := errors.New("stdErr")
suite.Equal(ErrCode(stdErr), GeneralCode)
err = Wrap(stdErr, "wrap stdErr")
suite.Equal(ErrCode(stdErr), GeneralCode)
}
func (suite *ErrorTestSuite) TestErrs() {
err := New("root").WithCode(ConflictCode)
suite.Equal(`{"errors":[{"code":"CONFLICT","message":"root"}]}`, NewErrs(err).Error())
}
func (suite *ErrorTestSuite) TestNotFoundError() {
root := errors.New("something is not found")
err := NotFoundError(root)
suite.Equal(`resource not found: something is not found`, err.Error())
root = errors.New("something is not found")
err = NotFoundError(root).WithMessage("asset not found")
suite.Equal(`asset not found: something is not found`, err.Error())
}
func (suite *ErrorTestSuite) TestIsErr() {
stdErr := errors.New("stdErr")
err := Wrap(stdErr, "root")
targetErr := Wrap(err, "target err").WithCode(ConflictCode)
suite.True(IsErr(targetErr, ConflictCode))
}
func (suite *ErrorTestSuite) TestCause() {
// self
root := New("root")
suite.Equal(root, Cause(root))
root = New("root")
cause1 := Wrap(root, "err1")
cause2 := Wrap(cause1, "err2")
cause3 := Wrap(cause2, "err3")
suite.Equal(root, Cause(cause3))
}
func (suite *ErrorTestSuite) TestCauseStd() {
root := errors.New("stdErr")
suite.Equal(root, Cause(root))
root = errors.New("stdErr")
cause1 := Wrap(root, "err1")
cause2 := Wrap(cause1, "err2")
cause3 := Wrap(cause2, "err3")
suite.Equal(root, Cause(cause3))
}
func TestErrorTestSuite(t *testing.T) { func TestErrorTestSuite(t *testing.T) {
suite.Run(t, &ErrorTestSuite{}) suite.Run(t, &ErrorTestSuite{})
} }