[#278] client: Support wrapped errors in error checkers

Client errors are quite often wrapped in context. When checking a
specific error, it is required not to lose the ability to determine it,
regardless of the attached context. In previous implementation `IsErr*`
functions didn't support wrapped errors.

Make `IsErr*` functions to preliminarily unwrap `error` argument before
type assertion. Use `errors.Unwrap` for this instead of `errors.As`
since the latter has the overhead of filling in an error.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2022-06-27 10:39:20 +03:00 committed by fyrchik
parent 40942affe9
commit 09ed6077f9
2 changed files with 22 additions and 7 deletions

View file

@ -1,11 +1,24 @@
package client package client
import apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" import (
"errors"
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
)
// unwraps err using errors.Unwrap and returns the result.
func unwrapErr(err error) error {
for e := errors.Unwrap(err); e != nil; e = errors.Unwrap(err) {
err = e
}
return err
}
// IsErrContainerNotFound checks if err corresponds to NeoFS status // IsErrContainerNotFound checks if err corresponds to NeoFS status
// return corresponding to missing container. // return corresponding to missing container. Supports wrapped errors.
func IsErrContainerNotFound(err error) bool { func IsErrContainerNotFound(err error) bool {
switch err.(type) { switch unwrapErr(err).(type) {
default: default:
return false return false
case case
@ -16,9 +29,9 @@ func IsErrContainerNotFound(err error) bool {
} }
// IsErrObjectNotFound checks if err corresponds to NeoFS status // IsErrObjectNotFound checks if err corresponds to NeoFS status
// return corresponding to missing object. // return corresponding to missing object. Supports wrapped errors.
func IsErrObjectNotFound(err error) bool { func IsErrObjectNotFound(err error) bool {
switch err.(type) { switch unwrapErr(err).(type) {
default: default:
return false return false
case case
@ -29,9 +42,9 @@ func IsErrObjectNotFound(err error) bool {
} }
// IsErrObjectAlreadyRemoved checks if err corresponds to NeoFS status // IsErrObjectAlreadyRemoved checks if err corresponds to NeoFS status
// return corresponding to already removed object. // return corresponding to already removed object. Supports wrapped errors.
func IsErrObjectAlreadyRemoved(err error) bool { func IsErrObjectAlreadyRemoved(err error) bool {
switch err.(type) { switch unwrapErr(err).(type) {
default: default:
return false return false
case case

View file

@ -1,6 +1,7 @@
package client_test package client_test
import ( import (
"fmt"
"testing" "testing"
"github.com/nspcc-dev/neofs-sdk-go/client" "github.com/nspcc-dev/neofs-sdk-go/client"
@ -39,6 +40,7 @@ func TestErrors(t *testing.T) {
for i := range tc.errs { for i := range tc.errs {
require.True(t, tc.check(tc.errs[i]), tc.errs[i]) require.True(t, tc.check(tc.errs[i]), tc.errs[i])
require.True(t, tc.check(fmt.Errorf("some context: %w", tc.errs[i])), tc.errs[i])
} }
} }
} }