Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions errdefs/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,23 @@ func TestSystem(t *testing.T) {
t.Fatalf("expected system error, got: %T", wrapped)
}
}

func TestIntentionallyShadowed(t *testing.T) {
var (
rootErr = errors.New("root error")

// Some code resulted in a "not found" error
notFoundErr = NotFound(rootErr)

// But a "not found" error should be considered a "invalid parameter",
// so it's intentionally wrapped.
actualErr = InvalidParameter(notFoundErr)
)

if !IsInvalidParameter(actualErr) {
t.Errorf("expected invalid parameter error, got %T", actualErr)
}
if IsNotFound(actualErr) {
t.Errorf("not found error should've been masked by an invalid parameter error, but got %T", actualErr)
}
}
Comment on lines +284 to +302
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed; this test passes with our errdefs, but fails with containerd's implementation 🤔

80 changes: 15 additions & 65 deletions errdefs/is.go
Original file line number Diff line number Diff line change
@@ -1,123 +1,73 @@
package errdefs

import (
"context"
"errors"
)

type causer interface {
Cause() error
}

type wrapErr interface {
Unwrap() error
}

func getImplementer(err error) error {
switch e := err.(type) {
case
ErrNotFound,
ErrInvalidParameter,
ErrConflict,
ErrUnauthorized,
ErrUnavailable,
ErrForbidden,
ErrSystem,
ErrNotModified,
ErrNotImplemented,
ErrCancelled,
ErrDeadline,
ErrDataLoss,
ErrUnknown:
return err
case causer:
return getImplementer(e.Cause())
case wrapErr:
return getImplementer(e.Unwrap())
default:
return err
}
}
import cerrdefs "github.com/containerd/errdefs"

// IsNotFound returns if the passed in error is an [ErrNotFound],
func IsNotFound(err error) bool {
_, ok := getImplementer(err).(ErrNotFound)
return ok
return cerrdefs.IsNotFound(err)
}

// IsInvalidParameter returns if the passed in error is an [ErrInvalidParameter].
func IsInvalidParameter(err error) bool {
_, ok := getImplementer(err).(ErrInvalidParameter)
return ok
return cerrdefs.IsInvalidArgument(err)
}

// IsConflict returns if the passed in error is an [ErrConflict].
func IsConflict(err error) bool {
_, ok := getImplementer(err).(ErrConflict)
return ok
return cerrdefs.IsConflict(err)
}

// IsUnauthorized returns if the passed in error is an [ErrUnauthorized].
func IsUnauthorized(err error) bool {
_, ok := getImplementer(err).(ErrUnauthorized)
return ok
return cerrdefs.IsUnauthorized(err)
}

// IsUnavailable returns if the passed in error is an [ErrUnavailable].
func IsUnavailable(err error) bool {
_, ok := getImplementer(err).(ErrUnavailable)
return ok
return cerrdefs.IsUnavailable(err)
}

// IsForbidden returns if the passed in error is an [ErrForbidden].
func IsForbidden(err error) bool {
_, ok := getImplementer(err).(ErrForbidden)
return ok
return cerrdefs.IsPermissionDenied(err)
}

// IsSystem returns if the passed in error is an [ErrSystem].
func IsSystem(err error) bool {
_, ok := getImplementer(err).(ErrSystem)
return ok
return cerrdefs.IsInternal(err)
}

// IsNotModified returns if the passed in error is an [ErrNotModified].
func IsNotModified(err error) bool {
_, ok := getImplementer(err).(ErrNotModified)
return ok
return cerrdefs.IsNotModified(err)
}

// IsNotImplemented returns if the passed in error is an [ErrNotImplemented].
func IsNotImplemented(err error) bool {
_, ok := getImplementer(err).(ErrNotImplemented)
return ok
return cerrdefs.IsNotImplemented(err)
}

// IsUnknown returns if the passed in error is an [ErrUnknown].
func IsUnknown(err error) bool {
_, ok := getImplementer(err).(ErrUnknown)
return ok
return cerrdefs.IsUnknown(err)
}

// IsCancelled returns if the passed in error is an [ErrCancelled].
func IsCancelled(err error) bool {
_, ok := getImplementer(err).(ErrCancelled)
return ok
return cerrdefs.IsCanceled(err)
}

// IsDeadline returns if the passed in error is an [ErrDeadline].
func IsDeadline(err error) bool {
_, ok := getImplementer(err).(ErrDeadline)
return ok
return cerrdefs.IsDeadlineExceeded(err)
}

// IsDataLoss returns if the passed in error is an [ErrDataLoss].
func IsDataLoss(err error) bool {
_, ok := getImplementer(err).(ErrDataLoss)
return ok
return cerrdefs.IsDataLoss(err)
}

// IsContext returns if the passed in error is due to context cancellation or deadline exceeded.
func IsContext(err error) bool {
return errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)
return cerrdefs.IsCanceled(err) || cerrdefs.IsDeadlineExceeded(err)
}
Loading