Recoverable and Non-Recoverable errors (#232)
GraphConnector exports 2 error types. Recoverable and NonRecoverable. The package also implements error checks to confirm if errors are one of the exported types.
This commit is contained in:
parent
60eb8eec08
commit
3ee7ff0c0b
@ -199,7 +199,7 @@ func (gc *GraphConnector) RestoreMessages(ctx context.Context, dc DataCollection
|
|||||||
sentMessage, err := gc.client.UsersById(user).MailFoldersById(address).Messages().Post(clone)
|
sentMessage, err := gc.client.UsersById(user).MailFoldersById(address).Messages().Post(clone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = support.WrapAndAppend(data.UUID()+": "+
|
errs = support.WrapAndAppend(data.UUID()+": "+
|
||||||
support.ConnectorStackErrorTrace(ctx, err), err, errs)
|
support.ConnectorStackErrorTrace(err), err, errs)
|
||||||
continue
|
continue
|
||||||
// TODO: Add to retry Handler for the for failure
|
// TODO: Add to retry Handler for the for failure
|
||||||
}
|
}
|
||||||
@ -275,7 +275,8 @@ func (gc *GraphConnector) serializeMessages(ctx context.Context, user string) ([
|
|||||||
}
|
}
|
||||||
err = objectWriter.WriteObjectValue("", message)
|
err = objectWriter.WriteObjectValue("", message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = support.WrapAndAppend(*message.GetId(), err, errs)
|
errs = support.WrapAndAppend(*message.GetId(), support.SetNonRecoverableError(err),
|
||||||
|
errs)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
byteArray, err = objectWriter.GetSerializedContent()
|
byteArray, err = objectWriter.GetSerializedContent()
|
||||||
@ -321,3 +322,15 @@ func (gc *GraphConnector) Status() string {
|
|||||||
}
|
}
|
||||||
return gc.status.String()
|
return gc.status.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsRecoverableError returns true iff error is a RecoverableGCEerror
|
||||||
|
func IsRecoverableError(e error) bool {
|
||||||
|
var recoverable *support.RecoverableGCError
|
||||||
|
return errors.As(e, &recoverable)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNonRecoverableError returns true iff error is a NonRecoverableGCEerror
|
||||||
|
func IsNonRecoverableError(e error) bool {
|
||||||
|
var nonRecoverable *support.NonRecoverableGCError
|
||||||
|
return errors.As(e, &nonRecoverable)
|
||||||
|
}
|
||||||
|
|||||||
@ -46,12 +46,12 @@ func (suite *GraphConnectorIntegrationSuite) TestGraphConnector() {
|
|||||||
suite.NotNil(suite.connector)
|
suite.NotNil(suite.connector)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiconnectedGraphConnectorSuite struct {
|
type DisconnectedGraphConnectorSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDisconnectedGraphSuite(t *testing.T) {
|
func TestDisconnectedGraphSuite(t *testing.T) {
|
||||||
suite.Run(t, new(DiconnectedGraphConnectorSuite))
|
suite.Run(t, new(DisconnectedGraphConnectorSuite))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_setTenantUsers() {
|
func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_setTenantUsers() {
|
||||||
@ -92,7 +92,7 @@ func (suite *GraphConnectorIntegrationSuite) TestGraphConnector_restoreMessages(
|
|||||||
assert.NoError(suite.T(), err)
|
assert.NoError(suite.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *DiconnectedGraphConnectorSuite) TestBadConnection() {
|
func (suite *DisconnectedGraphConnectorSuite) TestBadConnection() {
|
||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
@ -144,7 +144,7 @@ func Contains(elems []string, value string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *DiconnectedGraphConnectorSuite) TestBuild() {
|
func (suite *DisconnectedGraphConnectorSuite) TestBuild() {
|
||||||
names := make(map[string]string)
|
names := make(map[string]string)
|
||||||
names["Al"] = "Bundy"
|
names["Al"] = "Bundy"
|
||||||
names["Ellen"] = "Ripley"
|
names["Ellen"] = "Ripley"
|
||||||
@ -160,7 +160,7 @@ func (suite *DiconnectedGraphConnectorSuite) TestBuild() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *DiconnectedGraphConnectorSuite) TestInterfaceAlignment() {
|
func (suite *DisconnectedGraphConnectorSuite) TestInterfaceAlignment() {
|
||||||
var dc DataCollection
|
var dc DataCollection
|
||||||
concrete := NewExchangeDataCollection("Check", []string{"interface", "works"})
|
concrete := NewExchangeDataCollection("Check", []string{"interface", "works"})
|
||||||
dc = &concrete
|
dc = &concrete
|
||||||
@ -168,7 +168,7 @@ func (suite *DiconnectedGraphConnectorSuite) TestInterfaceAlignment() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *DiconnectedGraphConnectorSuite) TestGraphConnector_Status() {
|
func (suite *DisconnectedGraphConnectorSuite) TestGraphConnector_Status() {
|
||||||
gc := GraphConnector{}
|
gc := GraphConnector{}
|
||||||
suite.Equal(len(gc.Status()), 0)
|
suite.Equal(len(gc.Status()), 0)
|
||||||
status, err := support.CreateStatus(support.Restore, 12, 9, 8,
|
status, err := support.CreateStatus(support.Restore, 12, 9, 8,
|
||||||
@ -177,3 +177,50 @@ func (suite *DiconnectedGraphConnectorSuite) TestGraphConnector_Status() {
|
|||||||
gc.SetStatus(*status)
|
gc.SetStatus(*status)
|
||||||
suite.Greater(len(gc.Status()), 0)
|
suite.Greater(len(gc.Status()), 0)
|
||||||
}
|
}
|
||||||
|
func (suite *DisconnectedGraphConnectorSuite) TestGraphConnector_ErrorChecking() {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
returnRecoverable bool
|
||||||
|
returnNonRecoverable bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Neither Option",
|
||||||
|
err: errors.New("regular error"),
|
||||||
|
returnRecoverable: false,
|
||||||
|
returnNonRecoverable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Validate Recoverable",
|
||||||
|
err: support.SetRecoverableError(errors.New("Recoverable")),
|
||||||
|
returnRecoverable: true,
|
||||||
|
returnNonRecoverable: false,
|
||||||
|
},
|
||||||
|
{name: "Validate NonRecoverable",
|
||||||
|
err: support.SetNonRecoverableError(errors.New("Non-recoverable")),
|
||||||
|
returnRecoverable: false,
|
||||||
|
returnNonRecoverable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Wrapped Recoverable",
|
||||||
|
err: support.SetRecoverableError(support.WrapAndAppend(
|
||||||
|
"Wrapped Recoverable", errors.New("Recoverable"), nil)),
|
||||||
|
returnRecoverable: true,
|
||||||
|
returnNonRecoverable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "On Nil",
|
||||||
|
err: nil,
|
||||||
|
returnRecoverable: false,
|
||||||
|
returnNonRecoverable: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
recoverable := IsRecoverableError(test.err)
|
||||||
|
nonRecoverable := IsNonRecoverableError(test.err)
|
||||||
|
suite.Equal(recoverable, test.returnRecoverable, "Expected: %v received %v", test.returnRecoverable, recoverable)
|
||||||
|
suite.Equal(nonRecoverable, test.returnNonRecoverable)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package support
|
package support
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -9,10 +8,35 @@ import (
|
|||||||
multierror "github.com/hashicorp/go-multierror"
|
multierror "github.com/hashicorp/go-multierror"
|
||||||
msgraph_errors "github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors"
|
msgraph_errors "github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/alcionai/corso/pkg/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GraphConnector has two types of errors that are exported
|
||||||
|
// RecoverableGCError is a query error that can be overcome with time
|
||||||
|
type RecoverableGCError struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rgc *RecoverableGCError) Error() string {
|
||||||
|
return rgc.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetRecoverableError(e error) error {
|
||||||
|
return &RecoverableGCError{err: e}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NonRecoverableGCError is a permanent query error
|
||||||
|
type NonRecoverableGCError struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nrgc *NonRecoverableGCError) Error() string {
|
||||||
|
return nrgc.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetNonRecoverableError(e error) error {
|
||||||
|
return &NonRecoverableGCError{err: e}
|
||||||
|
}
|
||||||
|
|
||||||
// WrapErrorAndAppend helper function used to attach identifying information to an error
|
// WrapErrorAndAppend helper function used to attach identifying information to an error
|
||||||
// and return it as a mulitierror
|
// and return it as a mulitierror
|
||||||
func WrapAndAppend(identifier string, e error, previous error) error {
|
func WrapAndAppend(identifier string, e error, previous error) error {
|
||||||
@ -42,10 +66,10 @@ func GetNumberOfErrors(err error) int {
|
|||||||
// ListErrors is a helper method used to return the string of errors when
|
// ListErrors is a helper method used to return the string of errors when
|
||||||
// the multiError library is used.
|
// the multiError library is used.
|
||||||
// depends on ConnectorStackErrorTrace
|
// depends on ConnectorStackErrorTrace
|
||||||
func ListErrors(ctx context.Context, multi multierror.Error) string {
|
func ListErrors(multi multierror.Error) string {
|
||||||
aString := ""
|
aString := ""
|
||||||
for idx, err := range multi.Errors {
|
for idx, err := range multi.Errors {
|
||||||
detail := ConnectorStackErrorTrace(ctx, err)
|
detail := ConnectorStackErrorTrace(err)
|
||||||
if detail == "" {
|
if detail == "" {
|
||||||
detail = fmt.Sprintf("%v", err)
|
detail = fmt.Sprintf("%v", err)
|
||||||
}
|
}
|
||||||
@ -67,7 +91,7 @@ func concatenateStringFromPointers(orig string, pointers []*string) string {
|
|||||||
|
|
||||||
// ConnectorStackErrorTrace is a helper function that wraps the
|
// ConnectorStackErrorTrace is a helper function that wraps the
|
||||||
// stack trace for oDataError types from querying the M365 back store.
|
// stack trace for oDataError types from querying the M365 back store.
|
||||||
func ConnectorStackErrorTrace(ctx context.Context, e error) string {
|
func ConnectorStackErrorTrace(e error) string {
|
||||||
eMessage := ""
|
eMessage := ""
|
||||||
if oDataError, ok := e.(msgraph_errors.ODataErrorable); ok {
|
if oDataError, ok := e.(msgraph_errors.ODataErrorable); ok {
|
||||||
// Get MainError
|
// Get MainError
|
||||||
@ -99,7 +123,6 @@ func ConnectorStackErrorTrace(ctx context.Context, e error) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if inners != nil {
|
if inners != nil {
|
||||||
logger.Ctx(ctx).Debug("error contains inner errors")
|
|
||||||
eMessage = eMessage + "\nConnector Section:"
|
eMessage = eMessage + "\nConnector Section:"
|
||||||
client := inners.GetClientRequestId()
|
client := inners.GetClientRequestId()
|
||||||
rId := inners.GetRequestId()
|
rId := inners.GetRequestId()
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package support
|
package support
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
@ -27,8 +26,8 @@ func (suite *GraphConnectorErrorSuite) TestWrapAndAppend() {
|
|||||||
suite.True(strings.Contains(returnErr.Error(), "arc376"))
|
suite.True(strings.Contains(returnErr.Error(), "arc376"))
|
||||||
suite.Error(returnErr)
|
suite.Error(returnErr)
|
||||||
multi := &multierror.Error{Errors: []error{err1, err2}}
|
multi := &multierror.Error{Errors: []error{err1, err2}}
|
||||||
suite.True(strings.Contains(ListErrors(context.Background(), *multi), "two")) // Does not contain the wrapped information
|
suite.True(strings.Contains(ListErrors(*multi), "two")) // Does not contain the wrapped information
|
||||||
suite.T().Log(ListErrors(context.Background(), *multi))
|
suite.T().Log(ListErrors(*multi))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *GraphConnectorErrorSuite) TestWrapAndAppend_OnVar() {
|
func (suite *GraphConnectorErrorSuite) TestWrapAndAppend_OnVar() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user