client: Use error in FromStatusV2, ToStatusV2 functions

Signed-off-by: Evgenii Baidakov <evgenii@nspcc.io>
This commit is contained in:
Evgenii Baidakov 2023-05-23 10:34:02 +04:00
parent 22ff96ad44
commit 26c1b26eec
No known key found for this signature in database
GPG key ID: 8733EE3D72CDB4DE
4 changed files with 47 additions and 104 deletions

View file

@ -197,12 +197,8 @@ func (x *contextCall) processResponse() bool {
}
// get result status
st := apistatus.FromStatusV2(x.resp.GetMetaHeader().GetStatus())
var errorExists bool
x.err, errorExists = st.(error)
return !errorExists
x.err = apistatus.FromStatusV2(x.resp.GetMetaHeader().GetStatus())
return x.err == nil
}
// processResponse verifies response signature.
@ -211,12 +207,7 @@ func (c *Client) processResponse(resp responseV2) error {
return fmt.Errorf("invalid response signature: %w", err)
}
st := apistatus.FromStatusV2(resp.GetMetaHeader().GetStatus())
if err, ok := st.(error); ok {
return err
}
return nil
return apistatus.FromStatusV2(resp.GetMetaHeader().GetStatus())
}
// reads response (if rResp is set) and processes it. Result means success.

View file

@ -1,32 +0,0 @@
package apistatus
import (
"github.com/nspcc-dev/neofs-api-go/v2/status"
)
// SuccessDefaultV2 represents 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

@ -1,6 +1,7 @@
package apistatus
import (
"errors"
"fmt"
"github.com/nspcc-dev/neofs-api-go/v2/container"
@ -17,7 +18,7 @@ type StatusV2 interface {
ToStatusV2() *status.Status
}
// FromStatusV2 converts [status.Status] message structure to status instance. Inverse to [ToStatusV2] operation.
// FromStatusV2 converts [status.Status] message structure to error. Inverse to [ToStatusV2] 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.
@ -26,7 +27,7 @@ type StatusV2 interface {
// 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];
@ -49,9 +50,10 @@ type StatusV2 interface {
// Session failures:
// - [session.StatusTokenNotFound]: *[SessionTokenNotFound];
// - [session.StatusTokenExpired]: *[SessionTokenExpired];
func FromStatusV2(st *status.Status) any {
func FromStatusV2(st *status.Status) error {
var decoder interface {
fromStatusV2(*status.Status)
Error() string
}
switch code := st.Code(); {
@ -59,7 +61,7 @@ func FromStatusV2(st *status.Status) any {
//nolint:exhaustive
switch status.LocalizeSuccess(&code); code {
case status.OK:
decoder = new(SuccessDefaultV2)
return nil
}
case status.IsCommonFail(code):
switch status.LocalizeCommonFail(&code); code {
@ -114,19 +116,19 @@ func FromStatusV2(st *status.Status) any {
return decoder
}
// ToStatusV2 converts instance to status.Status message structure. Inverse to [FromStatusV2] operation.
// ToStatusV2 converts error to status.Status message structure. Inverse to [FromStatusV2] 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 any) *status.Status {
if v, ok := st.(StatusV2); ok {
return v.ToStatusV2()
func ToStatusV2(err error) *status.Status {
if err == nil {
return newStatusV2WithLocalCode(status.OK, status.GlobalizeSuccess)
}
err, isErrorExists := st.(error)
if !isErrorExists {
return newStatusV2WithLocalCode(status.OK, status.GlobalizeSuccess)
var instance StatusV2
if errors.As(err, &instance) {
return instance.ToStatusV2()
}
internalErrorStatus := newStatusV2WithLocalCode(status.Internal, status.GlobalizeCommonFail)

View file

@ -9,7 +9,7 @@ import (
)
func TestFromStatusV2(t *testing.T) {
type statusConstructor func() any
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() any {
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() any {
status: (statusConstructor)(func() error {
st := new(apistatus.WrongMagicNumber)
st.WriteCorrectMagic(322)
@ -72,7 +60,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
return new(apistatus.ObjectLocked)
}),
codeV2: 2050,
@ -83,7 +71,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
return new(apistatus.LockNonRegularObject)
}),
codeV2: 2051,
@ -94,7 +82,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
st := new(apistatus.ObjectAccessDenied)
st.WriteReason("any reason")
@ -108,7 +96,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
return new(apistatus.ObjectNotFound)
}),
codeV2: 2049,
@ -119,7 +107,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
return new(apistatus.ObjectAlreadyRemoved)
}),
codeV2: 2052,
@ -130,7 +118,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: statusConstructor(func() any {
status: statusConstructor(func() error {
return new(apistatus.ObjectOutOfRange)
}),
codeV2: 2053,
@ -141,7 +129,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
return new(apistatus.ContainerNotFound)
}),
codeV2: 3072,
@ -152,7 +140,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
return new(apistatus.EACLNotFound)
}),
codeV2: 3073,
@ -163,7 +151,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
return new(apistatus.SessionTokenNotFound)
}),
codeV2: 4096,
@ -174,7 +162,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
return new(apistatus.SessionTokenExpired)
}),
codeV2: 4097,
@ -185,7 +173,7 @@ func TestFromStatusV2(t *testing.T) {
},
},
{
status: (statusConstructor)(func() any {
status: (statusConstructor)(func() error {
return new(apistatus.NodeUnderMaintenance)
}),
codeV2: 1027,
@ -196,13 +184,11 @@ func TestFromStatusV2(t *testing.T) {
},
},
} {
var st any
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)
@ -212,7 +198,7 @@ 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)
@ -224,17 +210,13 @@ func TestFromStatusV2(t *testing.T) {
}
randomError := errors.New("garbage")
// some `st` in test-cases is int, bool, string
errFromStatus, ok := st.(error)
if ok {
for _, err := range testItem.compatibleErrs {
require.ErrorIs(t, errFromStatus, err)
require.NotErrorIs(t, randomError, err)
}
for _, err := range testItem.compatibleErrs {
require.ErrorIs(t, st, err)
require.NotErrorIs(t, randomError, err)
}
if testItem.checkAsErr != nil {
require.True(t, testItem.checkAsErr(errFromStatus))
}
if testItem.checkAsErr != nil {
require.True(t, testItem.checkAsErr(st))
}
}
}