Skip to content

Commit

Permalink
enhancement: add error origin information to the errorcode package
Browse files Browse the repository at this point in the history
  • Loading branch information
fschade committed Jun 19, 2024
1 parent 1f012ac commit c508439
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 146 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.10.0
github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781
github.com/cs3org/reva/v2 v2.19.2-0.20240613123928-7fb5f11a24cf
github.com/cs3org/reva/v2 v2.19.2-0.20240618080316-ed0273c9db9b
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/egirna/icap-client v0.1.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1025,8 +1025,8 @@ github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c=
github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME=
github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781 h1:BUdwkIlf8IS2FasrrPg8gGPHQPOrQ18MS1Oew2tmGtY=
github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva/v2 v2.19.2-0.20240613123928-7fb5f11a24cf h1:AQLf+bZfcEn4zKQiH5vLtBpOx7onvbCQ4Z9X4i6SKNM=
github.com/cs3org/reva/v2 v2.19.2-0.20240613123928-7fb5f11a24cf/go.mod h1:Rb2XnhpGKnH7k6WBFZlMygbyBxW6ma09Z4Uk+ro0v+A=
github.com/cs3org/reva/v2 v2.19.2-0.20240618080316-ed0273c9db9b h1:IPFiNd8Xev9WxAt+LkJUxnbyU8Y1rGi5Ha0S+ZNObr8=
github.com/cs3org/reva/v2 v2.19.2-0.20240618080316-ed0273c9db9b/go.mod h1:Rb2XnhpGKnH7k6WBFZlMygbyBxW6ma09Z4Uk+ro0v+A=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
Expand Down
23 changes: 0 additions & 23 deletions services/frontend/pkg/command/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package command
import (
"context"
"errors"
"fmt"

"github.com/cs3org/reva/v2/pkg/events"
"github.com/cs3org/reva/v2/pkg/events/stream"
Expand Down Expand Up @@ -187,25 +186,3 @@ func updateShareRequest(shareID *collaboration.ShareId, uid *user.UserId) *colla
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"state"}},
}
}

// getSharesList gets the list of all shares for the given user.
func getSharesList(ctx context.Context, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], uid *user.UserId) (*collaboration.ListReceivedSharesResponse, error) {
gwc, err := gatewaySelector.Next()
if err != nil {
return nil, err
}
shares, err := gwc.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{
Opaque: utils.AppendJSONToOpaque(nil, "userid", uid),
})
if err != nil {
return nil, err
}

if shares.Status.Code != rpc.Code_CODE_OK {
if shares.Status.Code == rpc.Code_CODE_NOT_FOUND {
return nil, fmt.Errorf("not found")
}
return nil, fmt.Errorf(shares.GetStatus().GetMessage())
}
return shares, nil
}
8 changes: 5 additions & 3 deletions services/graph/pkg/errorcode/cs3.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"

"github.com/cs3org/reva/v2/pkg/utils"
)

Expand All @@ -19,12 +20,13 @@ import (
// This function is particularly useful when dealing with CS3 responses,
// and a unified error handling within the application is necessary.
func FromCS3Status(status *cs3rpc.Status, inerr error, ignore ...cs3rpc.Code) error {
err := Error{errorCode: GeneralException, msg: "unspecified error has occurred", origin: ErrorOriginCS3}

if inerr != nil {
return Error{msg: inerr.Error(), errorCode: GeneralException}
err.msg = inerr.Error()
return err
}

err := Error{errorCode: GeneralException, msg: "unspecified error has occurred"}

if status != nil {
err.msg = status.GetMessage()
}
Expand Down
5 changes: 5 additions & 0 deletions services/graph/pkg/errorcode/cs3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ func TestFromCS3Status(t *testing.T) {
}

for _, test := range tests {
var e errorcode.Error
if errors.As(test.expected, &e) {
test.expected = e.WithOrigin(errorcode.ErrorOriginCS3)
}

if got := errorcode.FromCS3Status(test.status, test.err, test.ignore...); !reflect.DeepEqual(got, test.expected) {
t.Error("Test Failed: {} expected, received: {}", test.expected, got)
}
Expand Down
51 changes: 43 additions & 8 deletions services/graph/pkg/errorcode/errorcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,28 @@ import (
libregraph "github.com/owncloud/libre-graph-api-go"
)

// ErrorCode defines code as used in MS Graph - see https://docs.microsoft.com/en-us/graph/errors?context=graph%2Fapi%2F1.0&view=graph-rest-1.0
type ErrorCode int

// Error defines a custom error struct, containing and MS Graph error code and a textual error message
type Error struct {
errorCode ErrorCode
msg string
origin ErrorOrigin
}

// ErrorOrigin gives information about where the error originated
type ErrorOrigin int

const (
// ErrorOriginUnknown is the default error source
// and indicates that the error does not have any information about its origin
ErrorOriginUnknown ErrorOrigin = iota

// ErrorOriginCS3 indicates that the error originated from a CS3 service
ErrorOriginCS3
)

// ErrorCode defines code as used in MS Graph - see https://docs.microsoft.com/en-us/graph/errors?context=graph%2Fapi%2F1.0&view=graph-rest-1.0
type ErrorCode int

// List taken from https://github.com/microsoft/microsoft-graph-docs-1/blob/main/concepts/errors.md#code-property
const (
// AccessDenied defines the error if the caller doesn't have permission to perform the action.
Expand Down Expand Up @@ -148,7 +161,7 @@ func (e ErrorCode) String() string {
return errorCodes[e]
}

// Error return the concatenation of the error string and optional message
// Error returns the concatenation of the error string and optional message
func (e Error) Error() string {
errString := errorCodes[e.errorCode]
if e.msg != "" {
Expand All @@ -161,13 +174,35 @@ func (e Error) GetCode() ErrorCode {
return e.errorCode
}

// GetOrigin returns the source of the error
func (e Error) GetOrigin() ErrorOrigin {
return e.origin
}

// WithOrigin returns a new Error with the provided origin
func (e Error) WithOrigin(o ErrorOrigin) Error {
e.origin = o
return e
}

// RenderError render the Graph Error based on a code or default one
func RenderError(w http.ResponseWriter, r *http.Request, err error) {
var errcode Error
if errors.As(err, &errcode) {
errcode.Render(w, r)
e, ok := ToError(err)
if !ok {
GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}

GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
e.Render(w, r)
}

// ToError checks if the error is of type Error and returns it,
// the second parameter indicates if the error conversion was successful
func ToError(err error) (Error, bool) {
var e Error
if errors.As(err, &e) {
return e, true
}

return Error{}, false
}
17 changes: 9 additions & 8 deletions services/graph/pkg/service/v0/api_driveitem_permissions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
roleconversions "github.com/cs3org/reva/v2/pkg/conversions"
revactx "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/cs3org/reva/v2/pkg/utils"
cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"
"github.com/go-chi/chi/v5"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand All @@ -31,6 +25,13 @@ import (
"github.com/tidwall/gjson"
"google.golang.org/grpc"

roleconversions "github.com/cs3org/reva/v2/pkg/conversions"
revactx "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/cs3org/reva/v2/pkg/utils"
cs3mocks "github.com/cs3org/reva/v2/tests/cs3mocks/mocks"

"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/services/graph/mocks"
"github.com/owncloud/ocis/v2/services/graph/pkg/config/defaults"
Expand Down Expand Up @@ -249,7 +250,7 @@ var _ = Describe("DriveItemPermissionsService", func() {
statResponse.Status = status.NewNotFound(context.Background(), "not found")
permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(errorcode.New(errorcode.ItemNotFound, "not found")))
Expect(err).To(MatchError(errorcode.New(errorcode.ItemNotFound, "not found").WithOrigin(errorcode.ErrorOriginCS3)))
Expect(permission).To(BeZero())
})
})
Expand Down Expand Up @@ -999,7 +1000,7 @@ var _ = Describe("DriveItemPermissionsService", func() {

driveItemPermission.SetExpirationDateTime(expiration)
res, err := driveItemPermissionsService.UpdatePermission(context.Background(), driveItemId, "permissionid", driveItemPermission)
Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, "expiration date is in the past")))
Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, "expiration date is in the past").WithOrigin(errorcode.ErrorOriginCS3)))
Expect(res).To(BeZero())
})
})
Expand Down
13 changes: 10 additions & 3 deletions services/graph/pkg/service/v0/api_drives_drive_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ func (api DrivesDriveItemApi) DeleteDriveItem(w http.ResponseWriter, r *http.Req

shareID := ExtractShareIdFromResourceId(itemID)
if err := api.drivesDriveItemService.UnmountShare(ctx, shareID); err != nil {
api.logger.Debug().Err(err).Msg(err.Error())
api.logger.Debug().Err(err).Msg(ErrUnmountShare.Error())
errorcode.RenderError(w, r, err)
return
}
Expand Down Expand Up @@ -518,8 +518,15 @@ func (api DrivesDriveItemApi) CreateDriveItem(w http.ResponseWriter, r *http.Req

mountedShares, err := api.drivesDriveItemService.MountShare(ctx, &resourceId, requestDriveItem.GetName())
if err != nil {
api.logger.Debug().Err(err).Msg(err.Error())
errorcode.RenderError(w, r, err)
api.logger.Debug().Err(err).Msg(ErrMountShare.Error())

switch e, ok := errorcode.ToError(err); {
case ok && e.GetOrigin() == errorcode.ErrorOriginCS3 && e.GetCode() == errorcode.ItemNotFound:
ErrDriveItemConversion.Render(w, r)
default:
errorcode.RenderError(w, r, err)
}

return
}

Expand Down
18 changes: 9 additions & 9 deletions services/graph/pkg/service/v0/api_drives_drive_item_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ var _ = Describe("DrivesDriveItemService", func() {
Once()

_, err := drivesDriveItemService.GetShare(context.Background(), &collaborationv1beta1.ShareId{})
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error())))
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error()).WithOrigin(errorcode.ErrorOriginCS3)))
})

It("fails if share lookup does not report an error but the status is off", func() {
Expand All @@ -161,12 +161,12 @@ var _ = Describe("DrivesDriveItemService", func() {
EXPECT().
GetReceivedShare(context.Background(), mock.Anything, mock.Anything).
Return(&collaborationv1beta1.GetReceivedShareResponse{
Status: status.NewNotFound(context.Background(), someErr.Error()),
Status: status.NewInvalid(context.Background(), someErr.Error()),
}, nil).
Once()

_, err := drivesDriveItemService.GetShare(context.Background(), &collaborationv1beta1.ShareId{})
Expect(err).To(MatchError(errorcode.New(errorcode.ItemNotFound, someErr.Error())))
Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, someErr.Error()).WithOrigin(errorcode.ErrorOriginCS3)))
})

It("successfully returns a share", func() {
Expand Down Expand Up @@ -219,7 +219,7 @@ var _ = Describe("DrivesDriveItemService", func() {
request.Share.State = collaborationv1beta1.ShareState_SHARE_STATE_ACCEPTED
request.UpdateMask.Paths = append(request.UpdateMask.Paths, "state")
})
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error())))
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error()).WithOrigin(errorcode.ErrorOriginCS3)))
})

It("fails if share update does not report an error but the status is off", func() {
Expand All @@ -236,7 +236,7 @@ var _ = Describe("DrivesDriveItemService", func() {
request.Share.State = collaborationv1beta1.ShareState_SHARE_STATE_ACCEPTED
request.UpdateMask.Paths = append(request.UpdateMask.Paths, "state")
})
Expect(err).To(MatchError(errorcode.New(errorcode.ItemNotFound, someErr.Error())))
Expect(err).To(MatchError(errorcode.New(errorcode.ItemNotFound, someErr.Error()).WithOrigin(errorcode.ErrorOriginCS3)))
})
})

Expand Down Expand Up @@ -265,7 +265,7 @@ var _ = Describe("DrivesDriveItemService", func() {
request.Share.State = collaborationv1beta1.ShareState_SHARE_STATE_ACCEPTED
request.UpdateMask.Paths = append(request.UpdateMask.Paths, "state")
})
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error())))
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error()).WithOrigin(errorcode.ErrorOriginCS3)))
Expect(err.(interface{ Unwrap() []error }).Unwrap()).To(HaveLen(2))
Expect(shares).To(HaveLen(1))
})
Expand All @@ -281,7 +281,7 @@ var _ = Describe("DrivesDriveItemService", func() {
Once()

err := drivesDriveItemService.UnmountShare(context.Background(), &collaborationv1beta1.ShareId{})
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error())))
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error()).WithOrigin(errorcode.ErrorOriginCS3)))
})

It("requests only accepted shares to be unmounted", func() {
Expand Down Expand Up @@ -358,7 +358,7 @@ var _ = Describe("DrivesDriveItemService", func() {
Times(1)

err := drivesDriveItemService.UnmountShare(context.Background(), &collaborationv1beta1.ShareId{})
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error())))
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error()).WithOrigin(errorcode.ErrorOriginCS3)))
Expect(err.(interface{ Unwrap() []error }).Unwrap()).To(HaveLen(1))
})
})
Expand Down Expand Up @@ -436,7 +436,7 @@ var _ = Describe("DrivesDriveItemService", func() {
Times(3)

shares, err := drivesDriveItemService.MountShare(context.Background(), nil, "some")
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error())))
Expect(err).To(MatchError(errorcode.New(errorcode.GeneralException, someErr.Error()).WithOrigin(errorcode.ErrorOriginCS3)))
Expect(err.(interface{ Unwrap() []error }).Unwrap()).To(HaveLen(3))
Expect(shares).To(HaveLen(0))
})
Expand Down
Loading

0 comments on commit c508439

Please sign in to comment.