diff --git a/client/common.go b/client/common.go index 895e6ea..4542b1e 100644 --- a/client/common.go +++ b/client/common.go @@ -197,23 +197,17 @@ func (x *contextCall) processResponse() bool { } // get result status - st := apistatus.FromStatusV2(x.resp.GetMetaHeader().GetStatus()) - - successfulStatus := apistatus.IsSuccessful(st) - x.err = apistatus.ErrFromStatus(st) - - return successfulStatus + x.err = apistatus.ErrorFromV2(x.resp.GetMetaHeader().GetStatus()) + return x.err == nil } // processResponse verifies response signature. -func (c *Client) processResponse(resp responseV2) (apistatus.Status, error) { - err := verifyServiceMessage(resp) - if err != nil { - return nil, fmt.Errorf("invalid response signature: %w", err) +func (c *Client) processResponse(resp responseV2) error { + if err := verifyServiceMessage(resp); err != nil { + return fmt.Errorf("invalid response signature: %w", err) } - st := apistatus.FromStatusV2(resp.GetMetaHeader().GetStatus()) - return st, apistatus.ErrFromStatus(st) + return apistatus.ErrorFromV2(resp.GetMetaHeader().GetStatus()) } // reads response (if rResp is set) and processes it. Result means success. diff --git a/client/netmap.go b/client/netmap.go index 27614c1..90b248c 100644 --- a/client/netmap.go +++ b/client/netmap.go @@ -217,8 +217,7 @@ func (c *Client) NetMapSnapshot(ctx context.Context, _ PrmNetMapSnapshot) (*ResN } var res ResNetMapSnapshot - _, err = c.processResponse(resp) - if err != nil { + if err = c.processResponse(resp); err != nil { return nil, err } diff --git a/client/netmap_test.go b/client/netmap_test.go index 8a57436..7003db0 100644 --- a/client/netmap_test.go +++ b/client/netmap_test.go @@ -52,7 +52,7 @@ func (x *serverNetMap) netMapSnapshot(_ context.Context, req v2netmap.SnapshotRe var meta session.ResponseMetaHeader if !x.statusOK { - meta.SetStatus(statusErr.ToStatusV2()) + meta.SetStatus(statusErr.ErrorToV2()) } var resp v2netmap.SnapshotResponse diff --git a/client/object_delete.go b/client/object_delete.go index bcb9b84..72f9a38 100644 --- a/client/object_delete.go +++ b/client/object_delete.go @@ -156,8 +156,7 @@ func (c *Client) ObjectDelete(ctx context.Context, prm PrmObjectDelete) (*ResObj } var res ResObjectDelete - _, err = c.processResponse(resp) - if err != nil { + if err = c.processResponse(resp); err != nil { return nil, err } diff --git a/client/object_get.go b/client/object_get.go index bedfcba..4a506d7 100644 --- a/client/object_get.go +++ b/client/object_get.go @@ -133,7 +133,7 @@ func (x *ObjectReader) ReadHeader(dst *object.Object) bool { return false } - _, x.err = x.client.processResponse(&resp) + x.err = x.client.processResponse(&resp) if x.err != nil { return false } @@ -186,7 +186,7 @@ func (x *ObjectReader) readChunk(buf []byte) (int, bool) { return read, false } - _, x.err = x.client.processResponse(&resp) + x.err = x.client.processResponse(&resp) if x.err != nil { return read, false } @@ -433,8 +433,7 @@ func (c *Client) ObjectHead(ctx context.Context, prm PrmObjectHead) (*ResObjectH } var res ResObjectHead - _, err = c.processResponse(resp) - if err != nil { + if err = c.processResponse(resp); err != nil { return nil, err } @@ -529,7 +528,7 @@ func (x *ObjectRangeReader) readChunk(buf []byte) (int, bool) { return read, false } - _, x.err = x.client.processResponse(&resp) + x.err = x.client.processResponse(&resp) if x.err != nil { return read, false } diff --git a/client/object_hash.go b/client/object_hash.go index 847a801..f87e631 100644 --- a/client/object_hash.go +++ b/client/object_hash.go @@ -195,8 +195,7 @@ func (c *Client) ObjectHash(ctx context.Context, prm PrmObjectHash) (*ResObjectH } var res ResObjectHash - _, err = c.processResponse(resp) - if err != nil { + if err = c.processResponse(resp); err != nil { return nil, err } diff --git a/client/object_put.go b/client/object_put.go index e117e2f..806b502 100644 --- a/client/object_put.go +++ b/client/object_put.go @@ -12,7 +12,6 @@ import ( "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" v2session "github.com/nspcc-dev/neofs-api-go/v2/session" "github.com/nspcc-dev/neofs-sdk-go/bearer" - apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto" "github.com/nspcc-dev/neofs-sdk-go/object" @@ -206,8 +205,7 @@ func (x *ObjectWriter) Close() (*ResObjectPut, error) { return nil, x.err } - _, x.err = x.client.processResponse(&x.respV2) - if x.err != nil { + if x.err = x.client.processResponse(&x.respV2); x.err != nil { return nil, x.err } @@ -275,12 +273,12 @@ func (x *objectWriter) InitDataStream(header object.Object) (io.Writer, error) { }, nil } - res, err := stream.Close() + _, err = stream.Close() if err != nil { return nil, err } - return nil, apistatus.ErrFromStatus(res) + return nil, errors.New("unexpected error") } type payloadWriter struct { @@ -296,12 +294,12 @@ func (x *payloadWriter) Write(p []byte) (int, error) { } func (x *payloadWriter) Close() error { - res, err := x.stream.Close() + _, err := x.stream.Close() if err != nil { return err } - return apistatus.ErrFromStatus(res) + return nil } // CreateObject creates new NeoFS object with given payload data and stores it diff --git a/client/object_search.go b/client/object_search.go index bdd6481..3f8b9c4 100644 --- a/client/object_search.go +++ b/client/object_search.go @@ -125,7 +125,7 @@ func (x *ObjectListReader) Read(buf []oid.ID) (int, bool) { return read, false } - _, x.err = x.client.processResponse(&resp) + x.err = x.client.processResponse(&resp) if x.err != nil { return read, false } diff --git a/client/status/common.go b/client/status/common.go index ec01eb9..e3e5b04 100644 --- a/client/status/common.go +++ b/client/status/common.go @@ -27,7 +27,7 @@ var ( ) // ServerInternal describes failure statuses related to internal server errors. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. // // The status is purely informative, the client should not go into details of the error except for debugging needs. type ServerInternal struct { @@ -51,18 +51,18 @@ func (x ServerInternal) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *ServerInternal) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: INTERNAL; // - string message: empty; // - details: empty. -func (x ServerInternal) ToStatusV2() *status.Status { +func (x ServerInternal) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(status.Internal, status.GlobalizeCommonFail)) return &x.v2 } @@ -87,7 +87,7 @@ func WriteInternalServerErr(x *ServerInternal, err error) { } // WrongMagicNumber describes failure status related to incorrect network magic. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type WrongMagicNumber struct { v2 status.Status } @@ -109,18 +109,18 @@ func (x WrongMagicNumber) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *WrongMagicNumber) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: WRONG_MAGIC_NUMBER; // - string message: empty; // - details: empty. -func (x WrongMagicNumber) ToStatusV2() *status.Status { +func (x WrongMagicNumber) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(status.WrongMagicNumber, status.GlobalizeCommonFail)) return &x.v2 } @@ -165,7 +165,7 @@ func (x WrongMagicNumber) CorrectMagic() (magic uint64, ok int8) { } // SignatureVerification describes failure status related to signature verification. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type SignatureVerification struct { v2 status.Status } @@ -194,19 +194,19 @@ func (x SignatureVerification) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *SignatureVerification) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: SIGNATURE_VERIFICATION_FAIL; -// - string message: written message via SetMessage or +// - string message: written message via [SignatureVerification.SetMessage] or // "signature verification failed" as a default message; // - details: empty. -func (x SignatureVerification) ToStatusV2() *status.Status { +func (x SignatureVerification) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(status.SignatureVerificationFail, status.GlobalizeCommonFail)) if x.v2.Message() == "" { @@ -233,7 +233,7 @@ func (x SignatureVerification) Message() string { } // NodeUnderMaintenance describes failure status for nodes being under maintenance. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type NodeUnderMaintenance struct { v2 status.Status } @@ -267,14 +267,14 @@ func (x *NodeUnderMaintenance) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: NODE_UNDER_MAINTENANCE; -// - string message: written message via SetMessage or +// - string message: written message via [NodeUnderMaintenance.SetMessage] or // "node is under maintenance" as a default message; // - details: empty. -func (x NodeUnderMaintenance) ToStatusV2() *status.Status { +func (x NodeUnderMaintenance) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(status.NodeUnderMaintenance, status.GlobalizeCommonFail)) if x.v2.Message() == "" { x.v2.SetMessage(defaultNodeUnderMaintenanceMsg) diff --git a/client/status/common_test.go b/client/status/common_test.go index 032263a..5576f48 100644 --- a/client/status/common_test.go +++ b/client/status/common_test.go @@ -14,14 +14,14 @@ func TestServerInternal_Message(t *testing.T) { var st apistatus.ServerInternal res := st.Message() - resv2 := apistatus.ToStatusV2(st).Message() + resv2 := apistatus.ErrorToV2(st).Message() require.Empty(t, res) require.Empty(t, resv2) st.SetMessage(msg) res = st.Message() - resv2 = apistatus.ToStatusV2(st).Message() + resv2 = apistatus.ErrorToV2(st).Message() require.Equal(t, msg, res) require.Equal(t, msg, resv2) } @@ -42,7 +42,7 @@ func TestWrongMagicNumber_CorrectMagic(t *testing.T) { require.EqualValues(t, 1, ok) // corrupt the value - apistatus.ToStatusV2(st).IterateDetails(func(d *status.Detail) bool { + apistatus.ErrorToV2(st).IterateDetails(func(d *status.Detail) bool { d.SetValue([]byte{1, 2, 3}) // any slice with len != 8 return true }) @@ -64,7 +64,7 @@ func TestSignatureVerification(t *testing.T) { st.SetMessage(msg) - stV2 := st.ToStatusV2() + stV2 := st.ErrorToV2() require.Equal(t, msg, st.Message()) require.Equal(t, msg, stV2.Message()) @@ -73,7 +73,7 @@ func TestSignatureVerification(t *testing.T) { t.Run("empty to V2", func(t *testing.T) { var st apistatus.SignatureVerification - stV2 := st.ToStatusV2() + stV2 := st.ErrorToV2() require.Equal(t, "signature verification failed", stV2.Message()) }) @@ -84,7 +84,7 @@ func TestSignatureVerification(t *testing.T) { st.SetMessage(msg) - stV2 := st.ToStatusV2() + stV2 := st.ErrorToV2() require.Equal(t, msg, stV2.Message()) }) @@ -103,7 +103,7 @@ func TestNodeUnderMaintenance(t *testing.T) { st.SetMessage(msg) - stV2 := st.ToStatusV2() + stV2 := st.ErrorToV2() require.Equal(t, msg, st.Message()) require.Equal(t, msg, stV2.Message()) @@ -112,7 +112,7 @@ func TestNodeUnderMaintenance(t *testing.T) { t.Run("empty to V2", func(t *testing.T) { var st apistatus.NodeUnderMaintenance - stV2 := st.ToStatusV2() + stV2 := st.ErrorToV2() require.Empty(t, "", stV2.Message()) }) @@ -123,7 +123,7 @@ func TestNodeUnderMaintenance(t *testing.T) { st.SetMessage(msg) - stV2 := st.ToStatusV2() + stV2 := st.ErrorToV2() require.Equal(t, msg, stV2.Message()) }) diff --git a/client/status/container.go b/client/status/container.go index c643123..526d46f 100644 --- a/client/status/container.go +++ b/client/status/container.go @@ -17,7 +17,7 @@ var ( ) // ContainerNotFound describes status of the failure because of the missing container. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type ContainerNotFound struct { v2 status.Status } @@ -46,18 +46,18 @@ func (x ContainerNotFound) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *ContainerNotFound) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: CONTAINER_NOT_FOUND; // - string message: "container not found"; // - details: empty. -func (x ContainerNotFound) ToStatusV2() *status.Status { +func (x ContainerNotFound) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(container.StatusNotFound, container.GlobalizeFail)) x.v2.SetMessage(defaultContainerNotFoundMsg) return &x.v2 @@ -65,7 +65,7 @@ func (x ContainerNotFound) ToStatusV2() *status.Status { // EACLNotFound describes status of the failure because of the missing eACL // table. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type EACLNotFound struct { v2 status.Status } @@ -94,18 +94,18 @@ func (x EACLNotFound) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *EACLNotFound) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: EACL_NOT_FOUND; // - string message: "eACL not found"; // - details: empty. -func (x EACLNotFound) ToStatusV2() *status.Status { +func (x EACLNotFound) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(container.StatusEACLNotFound, container.GlobalizeFail)) x.v2.SetMessage(defaultEACLNotFoundMsg) return &x.v2 diff --git a/client/status/object.go b/client/status/object.go index 2726088..906cd8f 100644 --- a/client/status/object.go +++ b/client/status/object.go @@ -29,7 +29,7 @@ var ( ) // ObjectLocked describes status of the failure because of the locked object. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type ObjectLocked struct { v2 status.Status } @@ -58,25 +58,25 @@ func (x ObjectLocked) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *ObjectLocked) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: LOCKED; // - string message: "object is locked"; // - details: empty. -func (x ObjectLocked) ToStatusV2() *status.Status { +func (x ObjectLocked) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(object.StatusLocked, object.GlobalizeFail)) x.v2.SetMessage(defaultObjectLockedMsg) return &x.v2 } // LockNonRegularObject describes status returned on locking the non-regular object. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type LockNonRegularObject struct { v2 status.Status } @@ -105,25 +105,25 @@ func (x LockNonRegularObject) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *LockNonRegularObject) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: LOCK_NON_REGULAR_OBJECT; // - string message: "locking non-regular object is forbidden"; // - details: empty. -func (x LockNonRegularObject) ToStatusV2() *status.Status { +func (x LockNonRegularObject) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(object.StatusLockNonRegularObject, object.GlobalizeFail)) x.v2.SetMessage(defaultLockNonRegularObjectMsg) return &x.v2 } // ObjectAccessDenied describes status of the failure because of the access control violation. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type ObjectAccessDenied struct { v2 status.Status } @@ -152,18 +152,18 @@ func (x ObjectAccessDenied) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *ObjectAccessDenied) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: ACCESS_DENIED; // - string message: "access to object operation denied"; // - details: empty. -func (x ObjectAccessDenied) ToStatusV2() *status.Status { +func (x ObjectAccessDenied) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(object.StatusAccessDenied, object.GlobalizeFail)) x.v2.SetMessage(defaultObjectAccessDeniedMsg) return &x.v2 @@ -181,7 +181,7 @@ func (x ObjectAccessDenied) Reason() string { } // ObjectNotFound describes status of the failure because of the missing object. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type ObjectNotFound struct { v2 status.Status } @@ -210,18 +210,18 @@ func (x ObjectNotFound) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *ObjectNotFound) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: OBJECT_NOT_FOUND; // - string message: "object not found"; // - details: empty. -func (x ObjectNotFound) ToStatusV2() *status.Status { +func (x ObjectNotFound) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(object.StatusNotFound, object.GlobalizeFail)) x.v2.SetMessage(defaultObjectNotFoundMsg) return &x.v2 @@ -257,18 +257,18 @@ func (x ObjectAlreadyRemoved) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *ObjectAlreadyRemoved) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: OBJECT_ALREADY_REMOVED; // - string message: "object already removed"; // - details: empty. -func (x ObjectAlreadyRemoved) ToStatusV2() *status.Status { +func (x ObjectAlreadyRemoved) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(object.StatusAlreadyRemoved, object.GlobalizeFail)) x.v2.SetMessage(defaultObjectAlreadyRemovedMsg) return &x.v2 @@ -276,7 +276,7 @@ func (x ObjectAlreadyRemoved) ToStatusV2() *status.Status { // ObjectOutOfRange describes status of the failure because of the incorrect // provided object ranges. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type ObjectOutOfRange struct { v2 status.Status } @@ -305,18 +305,18 @@ func (x ObjectOutOfRange) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *ObjectOutOfRange) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: OUT_OF_RANGE; // - string message: "out of range"; // - details: empty. -func (x ObjectOutOfRange) ToStatusV2() *status.Status { +func (x ObjectOutOfRange) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(object.StatusOutOfRange, object.GlobalizeFail)) x.v2.SetMessage(defaultObjectOutOfRangeMsg) return &x.v2 diff --git a/client/status/object_test.go b/client/status/object_test.go index 2e34ecf..126588a 100644 --- a/client/status/object_test.go +++ b/client/status/object_test.go @@ -14,13 +14,13 @@ func TestObjectAccessDenied_WriteReason(t *testing.T) { res := st.Reason() require.Empty(t, res) - detailNum := apistatus.ToStatusV2(st).NumberOfDetails() + detailNum := apistatus.ErrorToV2(st).NumberOfDetails() require.Zero(t, detailNum) st.WriteReason(reason) res = st.Reason() require.Equal(t, reason, res) - detailNum = apistatus.ToStatusV2(st).NumberOfDetails() + detailNum = apistatus.ErrorToV2(st).NumberOfDetails() require.EqualValues(t, 1, detailNum) } diff --git a/client/status/session.go b/client/status/session.go index a6a04c0..6fc470d 100644 --- a/client/status/session.go +++ b/client/status/session.go @@ -17,7 +17,7 @@ var ( ) // SessionTokenNotFound describes status of the failure because of the missing session token. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type SessionTokenNotFound struct { v2 status.Status } @@ -46,25 +46,25 @@ func (x SessionTokenNotFound) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *SessionTokenNotFound) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: TOKEN_NOT_FOUND; // - string message: "session token not found"; // - details: empty. -func (x SessionTokenNotFound) ToStatusV2() *status.Status { +func (x SessionTokenNotFound) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(session.StatusTokenNotFound, session.GlobalizeFail)) x.v2.SetMessage(defaultSessionTokenNotFoundMsg) return &x.v2 } // SessionTokenExpired describes status of the failure because of the expired session token. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type SessionTokenExpired struct { v2 status.Status } @@ -93,18 +93,18 @@ func (x SessionTokenExpired) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *SessionTokenExpired) fromStatusV2(st *status.Status) { x.v2 = *st } -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. +// ErrorToV2 implements [StatusV2] interface method. +// If the value was returned by [ErrorFromV2], returns the source message. // Otherwise, returns message with // - code: TOKEN_EXPIRED; // - string message: "expired session token"; // - details: empty. -func (x SessionTokenExpired) ToStatusV2() *status.Status { +func (x SessionTokenExpired) ErrorToV2() *status.Status { x.v2.SetCode(globalizeCodeV2(session.StatusTokenExpired, session.GlobalizeFail)) x.v2.SetMessage(defaultSessionTokenExpiredMsg) return &x.v2 diff --git a/client/status/status.go b/client/status/status.go deleted file mode 100644 index a220f2f..0000000 --- a/client/status/status.go +++ /dev/null @@ -1,44 +0,0 @@ -package apistatus - -// Status defines a variety of NeoFS API status returns. -// -// All statuses are split into two disjoint subsets: successful and failed, and: -// - statuses that implement the build-in error interface are considered failed statuses; -// - all other value types are considered successes (nil is a default success). -// -// In Go code type of success can be determined by a type switch, failure - by a switch with errors.As calls. -// Nil should be considered as a success, and default switch section - as an unrecognized Status. -// -// To convert statuses into errors and vice versa, use functions ErrToStatus and ErrFromStatus, respectively. -// ErrFromStatus function returns nil for successful statuses. However, to simplify the check of statuses for success, -// IsSuccessful function should be used (try to avoid nil comparison). -// It should be noted that using direct typecasting is not a compatible approach. -// -// To transport statuses using the NeoFS API V2 protocol, see StatusV2 interface and FromStatusV2 and ToStatusV2 functions. -type Status any - -// ErrFromStatus converts Status instance to error if it is failed. Returns nil on successful Status. -// -// Note: direct assignment may not be compatibility-safe. -func ErrFromStatus(st Status) error { - if err, ok := st.(error); ok { - return err - } - - return nil -} - -// ErrToStatus converts the error instance to Status instance. -// -// Note: direct assignment may not be compatibility-safe. -func ErrToStatus(err error) Status { - return err -} - -// IsSuccessful checks if status is successful. -// -// Note: direct cast may not be compatibility-safe. -func IsSuccessful(st Status) bool { - _, ok := st.(error) - return !ok -} diff --git a/client/status/status_test.go b/client/status/status_test.go deleted file mode 100644 index 6dcdd95..0000000 --- a/client/status/status_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package apistatus_test - -import ( - "errors" - "testing" - - apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" - "github.com/stretchr/testify/require" -) - -func TestErrors(t *testing.T) { - t.Run("error source", func(t *testing.T) { - err := errors.New("some error") - - st := apistatus.ErrToStatus(err) - - success := apistatus.IsSuccessful(st) - require.False(t, success) - - res := apistatus.ErrFromStatus(st) - - require.ErrorIs(t, res, err) - }) - - t.Run("non-error source", func(t *testing.T) { - var st apistatus.Status = "any non-error type" - - success := apistatus.IsSuccessful(st) - require.True(t, success) - - res := apistatus.ErrFromStatus(st) - - require.Nil(t, res) - }) -} diff --git a/client/status/success.go b/client/status/success.go deleted file mode 100644 index bd9ee82..0000000 --- a/client/status/success.go +++ /dev/null @@ -1,32 +0,0 @@ -package apistatus - -import ( - "github.com/nspcc-dev/neofs-api-go/v2/status" -) - -// SuccessDefaultV2 represents Status instance of default success. Implements StatusV2. -type SuccessDefaultV2 struct { - isNil bool - - v2 *status.Status -} - -// implements local interface defined in FromStatusV2 func. -func (x *SuccessDefaultV2) fromStatusV2(st *status.Status) { - x.isNil = st == nil - x.v2 = st -} - -// ToStatusV2 implements StatusV2 interface method. -// If the value was returned by FromStatusV2, returns the source message. -// Otherwise, returns message with -// - code: OK; -// - string message: empty; -// - details: empty. -func (x SuccessDefaultV2) ToStatusV2() *status.Status { - if x.isNil || x.v2 != nil { - return x.v2 - } - - return newStatusV2WithLocalCode(status.OK, status.GlobalizeSuccess) -} diff --git a/client/status/unrecognized.go b/client/status/unrecognized.go index a48ee44..15a8e1e 100644 --- a/client/status/unrecognized.go +++ b/client/status/unrecognized.go @@ -9,7 +9,7 @@ import ( var ErrUnrecognizedStatusV2 UnrecognizedStatusV2 // UnrecognizedStatusV2 describes status of the uncertain failure. -// Instances provide [Status], [StatusV2] and error interfaces. +// Instances provide [StatusV2] and error interfaces. type UnrecognizedStatusV2 struct { v2 status.Status } @@ -28,7 +28,7 @@ func (x UnrecognizedStatusV2) Is(target error) bool { } } -// implements local interface defined in FromStatusV2 func. +// implements local interface defined in [ErrorFromV2] func. func (x *UnrecognizedStatusV2) fromStatusV2(st *status.Status) { x.v2 = *st } diff --git a/client/status/v2.go b/client/status/v2.go index 69ab264..8974ea2 100644 --- a/client/status/v2.go +++ b/client/status/v2.go @@ -1,6 +1,7 @@ package apistatus import ( + "errors" "fmt" "github.com/nspcc-dev/neofs-api-go/v2/container" @@ -9,26 +10,24 @@ import ( "github.com/nspcc-dev/neofs-api-go/v2/status" ) -// StatusV2 defines a variety of Status instances compatible with NeoFS API V2 protocol. +// StatusV2 defines a variety of status instances compatible with NeoFS API V2 protocol. // // Note: it is not recommended to use this type directly, it is intended for documentation of the library functionality. type StatusV2 interface { - Status - - // ToStatusV2 returns the status as github.com/nspcc-dev/neofs-api-go/v2/status.Status message structure. - ToStatusV2() *status.Status + // ErrorToV2 returns the status as github.com/nspcc-dev/neofs-api-go/v2/status.Status message structure. + ErrorToV2() *status.Status } -// FromStatusV2 converts status.Status message structure to Status instance. Inverse to ToStatusV2 operation. +// ErrorFromV2 converts [status.Status] message structure to error. Inverse to [ErrorToV2] operation. // -// If result is not nil, it implements StatusV2. This fact should be taken into account only when passing -// the result to the inverse function ToStatusV2, casts are not compatibility-safe. +// If result is not nil, it implements [StatusV2]. This fact should be taken into account only when passing +// the result to the inverse function [ErrorToV2], casts are not compatibility-safe. // -// Below is the mapping of return codes to Status instance types (with a description of parsing details). +// Below is the mapping of return codes to status instance types (with a description of parsing details). // Note: notice if the return type is a pointer. // // Successes: -// - [status.OK]: *[SuccessDefaultV2] (this also includes nil argument). +// - [status.OK]: nil (this also includes nil argument). // // Common failures: // - [status.Internal]: *[ServerInternal]; @@ -51,9 +50,10 @@ type StatusV2 interface { // Session failures: // - [session.StatusTokenNotFound]: *[SessionTokenNotFound]; // - [session.StatusTokenExpired]: *[SessionTokenExpired]; -func FromStatusV2(st *status.Status) Status { +func ErrorFromV2(st *status.Status) error { var decoder interface { fromStatusV2(*status.Status) + Error() string } switch code := st.Code(); { @@ -61,7 +61,7 @@ func FromStatusV2(st *status.Status) Status { //nolint:exhaustive switch status.LocalizeSuccess(&code); code { case status.OK: - decoder = new(SuccessDefaultV2) + return nil } case status.IsCommonFail(code): switch status.LocalizeCommonFail(&code); code { @@ -116,22 +116,23 @@ func FromStatusV2(st *status.Status) Status { return decoder } -// ToStatusV2 converts Status instance to status.Status message structure. Inverse to FromStatusV2 operation. +// ErrorToV2 converts error to status.Status message structure. Inverse to [ErrorFromV2] operation. // -// If argument is the StatusV2 instance, it is converted directly. -// Otherwise, successes are converted with status.OK code w/o details and message, -// failures - with status.Internal and error text message w/o details. -func ToStatusV2(st Status) *status.Status { - if v, ok := st.(StatusV2); ok { - return v.ToStatusV2() - } - - if IsSuccessful(st) { +// If argument is the [StatusV2] instance, it is converted directly. +// Otherwise, successes are converted with [status.OK] code w/o details and message, +// failures - with [status.Internal] and error text message w/o details. +func ErrorToV2(err error) *status.Status { + if err == nil { return newStatusV2WithLocalCode(status.OK, status.GlobalizeSuccess) } + var instance StatusV2 + if errors.As(err, &instance) { + return instance.ErrorToV2() + } + internalErrorStatus := newStatusV2WithLocalCode(status.Internal, status.GlobalizeCommonFail) - internalErrorStatus.SetMessage(st.(error).Error()) // type cast never panics because IsSuccessful() checks cast + internalErrorStatus.SetMessage(err.Error()) return internalErrorStatus } diff --git a/client/status/v2_test.go b/client/status/v2_test.go index 8993153..d38beb2 100644 --- a/client/status/v2_test.go +++ b/client/status/v2_test.go @@ -9,7 +9,7 @@ import ( ) func TestFromStatusV2(t *testing.T) { - type statusConstructor func() apistatus.Status + type statusConstructor func() error for _, testItem := range [...]struct { status any // Status or statusConstructor @@ -19,32 +19,20 @@ func TestFromStatusV2(t *testing.T) { checkAsErr func(error) bool }{ { - status: errors.New("some error"), + status: (statusConstructor)(func() error { + return errors.New("some error") + }), codeV2: 1024, messageV2: "some error", }, { - status: 1, + status: (statusConstructor)(func() error { + return nil + }), codeV2: 0, }, { - status: "text", - codeV2: 0, - }, - { - status: false, - codeV2: 0, - }, - { - status: true, - codeV2: 0, - }, - { - status: nil, - codeV2: 0, - }, - { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { st := new(apistatus.ServerInternal) st.SetMessage("internal error message") @@ -58,7 +46,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { st := new(apistatus.WrongMagicNumber) st.WriteCorrectMagic(322) @@ -72,7 +60,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { return new(apistatus.ObjectLocked) }), codeV2: 2050, @@ -83,7 +71,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { return new(apistatus.LockNonRegularObject) }), codeV2: 2051, @@ -94,7 +82,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { st := new(apistatus.ObjectAccessDenied) st.WriteReason("any reason") @@ -108,7 +96,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { return new(apistatus.ObjectNotFound) }), codeV2: 2049, @@ -119,7 +107,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { return new(apistatus.ObjectAlreadyRemoved) }), codeV2: 2052, @@ -130,7 +118,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: statusConstructor(func() apistatus.Status { + status: statusConstructor(func() error { return new(apistatus.ObjectOutOfRange) }), codeV2: 2053, @@ -141,7 +129,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { return new(apistatus.ContainerNotFound) }), codeV2: 3072, @@ -152,7 +140,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { return new(apistatus.EACLNotFound) }), codeV2: 3073, @@ -163,7 +151,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { return new(apistatus.SessionTokenNotFound) }), codeV2: 4096, @@ -174,7 +162,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { return new(apistatus.SessionTokenExpired) }), codeV2: 4097, @@ -185,7 +173,7 @@ func TestFromStatusV2(t *testing.T) { }, }, { - status: (statusConstructor)(func() apistatus.Status { + status: (statusConstructor)(func() error { return new(apistatus.NodeUnderMaintenance) }), codeV2: 1027, @@ -196,15 +184,13 @@ func TestFromStatusV2(t *testing.T) { }, }, } { - var st apistatus.Status + var st error + cons, ok := testItem.status.(statusConstructor) + require.True(t, ok) - if cons, ok := testItem.status.(statusConstructor); ok { - st = cons() - } else { - st = testItem.status - } + st = cons() - stv2 := apistatus.ToStatusV2(st) + stv2 := apistatus.ErrorToV2(st) // must generate the same status.Status message require.EqualValues(t, testItem.codeV2, stv2.Code()) @@ -212,27 +198,25 @@ func TestFromStatusV2(t *testing.T) { require.Equal(t, testItem.messageV2, stv2.Message()) } - _, ok := st.(apistatus.StatusV2) + _, ok = st.(apistatus.StatusV2) if ok { // restore and convert again - restored := apistatus.FromStatusV2(stv2) + restored := apistatus.ErrorFromV2(stv2) - res := apistatus.ToStatusV2(restored) + res := apistatus.ErrorToV2(restored) // must generate the same status.Status message require.Equal(t, stv2, res) } randomError := errors.New("garbage") - errFromStatus := apistatus.ErrFromStatus(st) - for _, err := range testItem.compatibleErrs { - require.ErrorIs(t, errFromStatus, err) + require.ErrorIs(t, st, err) require.NotErrorIs(t, randomError, err) } if testItem.checkAsErr != nil { - require.True(t, testItem.checkAsErr(errFromStatus)) + require.True(t, testItem.checkAsErr(st)) } } } diff --git a/pool/mock_test.go b/pool/mock_test.go index ccbe070..39a61da 100644 --- a/pool/mock_test.go +++ b/pool/mock_test.go @@ -8,7 +8,6 @@ import ( sessionv2 "github.com/nspcc-dev/neofs-api-go/v2/session" "github.com/nspcc-dev/neofs-sdk-go/accounting" sdkClient "github.com/nspcc-dev/neofs-sdk-go/client" - apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" "github.com/nspcc-dev/neofs-sdk-go/container" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto" @@ -27,7 +26,7 @@ type mockClient struct { errorOnCreateSession bool errorOnEndpointInfo bool errorOnNetworkInfo bool - stOnGetObject apistatus.Status + errOnGetObject error } func newMockClient(addr string, signer neofscrypto.Signer) *mockClient { @@ -60,8 +59,8 @@ func (m *mockClient) errOnDial() { m.errOnNetworkInfo() } -func (m *mockClient) statusOnGetObject(st apistatus.Status) { - m.stOnGetObject = st +func (m *mockClient) statusOnGetObject(err error) { + m.errOnGetObject = err } func newToken(signer neofscrypto.Signer) *session.Object { @@ -139,13 +138,12 @@ func (m *mockClient) objectDelete(context.Context, PrmObjectDelete) error { func (m *mockClient) objectGet(context.Context, PrmObjectGet) (ResGetObject, error) { var res ResGetObject - if m.stOnGetObject == nil { + if m.errOnGetObject == nil { return res, nil } - err := apistatus.ErrFromStatus(m.stOnGetObject) - m.updateErrorRate(err) - return res, err + m.updateErrorRate(m.errOnGetObject) + return res, m.errOnGetObject } func (m *mockClient) objectHead(context.Context, PrmObjectHead) (object.Object, error) {