Revise apistatus funcs (#419)

close #417
This commit is contained in:
Roman Khimov 2023-05-24 14:55:28 +03:00 committed by GitHub
commit 4d4c5fc70c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 163 additions and 303 deletions

View file

@ -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.

View file

@ -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
}

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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

View file

@ -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
}

View file

@ -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)

View file

@ -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())
})

View file

@ -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

View file

@ -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

View file

@ -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)
}

View file

@ -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

View file

@ -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
}

View file

@ -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)
})
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}
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))
}
}
}

View file

@ -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) {