From c837473a0f7eb902ec7a876e8e2ec8eaf369107c Mon Sep 17 00:00:00 2001 From: Ivan Valdes Date: Wed, 11 Sep 2024 16:28:34 -0700 Subject: [PATCH] api: wrap underlying EtcdError error Without wrapping, using `errors.Is()` (or even trying to compare the error with `==`) fails as EtcdError swallows the underlying error. Signed-off-by: Ivan Valdes --- api/v3rpc/rpctypes/error.go | 11 ++++++++--- api/v3rpc/rpctypes/error_test.go | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/api/v3rpc/rpctypes/error.go b/api/v3rpc/rpctypes/error.go index 28f8d7e435f..c630e454cbb 100644 --- a/api/v3rpc/rpctypes/error.go +++ b/api/v3rpc/rpctypes/error.go @@ -239,8 +239,9 @@ var ( // EtcdError defines gRPC server errors. // (https://github.com/grpc/grpc-go/blob/master/rpc_util.go#L319-L323) type EtcdError struct { - code codes.Code - desc string + code codes.Code + desc string + wrappedError error } // Code returns grpc/codes.Code. @@ -253,6 +254,10 @@ func (e EtcdError) Error() string { return e.desc } +func (e EtcdError) Unwrap() error { + return e.wrappedError +} + func Error(err error) error { if err == nil { return nil @@ -268,7 +273,7 @@ func Error(err error) error { } else { desc = verr.Error() } - return EtcdError{code: ev.Code(), desc: desc} + return EtcdError{code: ev.Code(), desc: desc, wrappedError: err} } func ErrorDesc(err error) string { diff --git a/api/v3rpc/rpctypes/error_test.go b/api/v3rpc/rpctypes/error_test.go index bf3e0c68027..3f95265ddfd 100644 --- a/api/v3rpc/rpctypes/error_test.go +++ b/api/v3rpc/rpctypes/error_test.go @@ -15,6 +15,7 @@ package rpctypes import ( + "errors" "testing" "google.golang.org/grpc/codes" @@ -40,3 +41,20 @@ func TestConvert(t *testing.T) { t.Fatalf("expected them to be equal, got %v / %v", ev2.Code(), e3.(EtcdError).Code()) } } + +func TestComparingWrappedError(t *testing.T) { + errTest := errors.New("test error") + e1 := Error(ErrGRPCEmptyKey) + e2 := Error(status.Error(codes.InvalidArgument, "etcdserver: key is not provided")) + e3 := Error(errTest) + + if !errors.Is(e1, ErrGRPCEmptyKey) { + t.Fatalf("expected %v to be an ErrGRPCEmptyKey wrapped error", e1) + } + if !errors.Is(e2, ErrGRPCEmptyKey) { + t.Fatalf("expected %v to be an ErrGRPCEmptyKey wrapped error", e1) + } + if !errors.Is(e3, errTest) { + t.Fatalf("expected %v to be an errTest wrapped error", e3) + } +}