add canSkipItemFailure handler func
adds a new func to the exchange backup handler: canskipItemFailure. This interface allows any handler to evaluate the provided error and runtime config to decide whether that error is able to be marked as skipped instead of return a recoverable error as per standard.
This commit is contained in:
parent
60438d9e60
commit
dd71a5528a
@ -88,6 +88,15 @@ func (bh mockBackupHandler) folderGetter() containerGetter { return
|
|||||||
func (bh mockBackupHandler) previewIncludeContainers() []string { return bh.previewIncludes }
|
func (bh mockBackupHandler) previewIncludeContainers() []string { return bh.previewIncludes }
|
||||||
func (bh mockBackupHandler) previewExcludeContainers() []string { return bh.previewExcludes }
|
func (bh mockBackupHandler) previewExcludeContainers() []string { return bh.previewExcludes }
|
||||||
|
|
||||||
|
func (bh mockBackupHandler) CanSkipItemFailure(
|
||||||
|
error,
|
||||||
|
string,
|
||||||
|
string,
|
||||||
|
control.Options,
|
||||||
|
) (fault.SkipCause, bool) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
func (bh mockBackupHandler) NewContainerCache(
|
func (bh mockBackupHandler) NewContainerCache(
|
||||||
userID string,
|
userID string,
|
||||||
) (string, graph.ContainerResolver) {
|
) (string, graph.ContainerResolver) {
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package exchange
|
package exchange
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
||||||
)
|
)
|
||||||
@ -52,3 +54,11 @@ func (h contactBackupHandler) NewContainerCache(
|
|||||||
getter: h.ac,
|
getter: h.ac,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h contactBackupHandler) CanSkipItemFailure(
|
||||||
|
error,
|
||||||
|
string, string,
|
||||||
|
control.Options,
|
||||||
|
) (fault.SkipCause, bool) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ContactsBackupHandlerUnitSuite struct {
|
||||||
|
tester.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContactsBackupHandlerUnitSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &ContactsBackupHandlerUnitSuite{Suite: tester.NewUnitSuite(t)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ContactsBackupHandlerUnitSuite) TestHandler_CanSkipItemFailure() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
h := newContactBackupHandler(api.Client{})
|
||||||
|
cause, result := h.CanSkipItemFailure(nil, "", "", control.Options{})
|
||||||
|
|
||||||
|
assert.False(t, result)
|
||||||
|
assert.Equal(t, fault.SkipCause(""), cause)
|
||||||
|
}
|
||||||
@ -1,6 +1,12 @@
|
|||||||
package exchange
|
package exchange
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
||||||
)
|
)
|
||||||
@ -52,3 +58,22 @@ func (h eventBackupHandler) NewContainerCache(
|
|||||||
getter: h.ac,
|
getter: h.ac,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h eventBackupHandler) CanSkipItemFailure(
|
||||||
|
err error,
|
||||||
|
resourceID, itemID string,
|
||||||
|
opts control.Options,
|
||||||
|
) (fault.SkipCause, bool) {
|
||||||
|
// yes, this is intentionally a todo. I'll get back to it.
|
||||||
|
if !errors.Is(err, clues.New("todo fix me")) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
itemIDs, ok := opts.SkipTheseEventsOnInstance503[resourceID]
|
||||||
|
if !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// strict equals required here. ids are case sensitive.
|
||||||
|
return fault.SkipKnownEventInstance503s, slices.Contains(itemIDs, itemID)
|
||||||
|
}
|
||||||
|
|||||||
109
src/internal/m365/collection/exchange/events_backup_test.go
Normal file
109
src/internal/m365/collection/exchange/events_backup_test.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/alcionai/clues"
|
||||||
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EventsBackupHandlerUnitSuite struct {
|
||||||
|
tester.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEventsBackupHandlerUnitSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &EventsBackupHandlerUnitSuite{Suite: tester.NewUnitSuite(t)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *EventsBackupHandlerUnitSuite) TestHandler_CanSkipItemFailure() {
|
||||||
|
var (
|
||||||
|
resourceID = uuid.NewString()
|
||||||
|
itemID = uuid.NewString()
|
||||||
|
)
|
||||||
|
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
opts control.Options
|
||||||
|
expect assert.BoolAssertionFunc
|
||||||
|
expectCause fault.SkipCause
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no config",
|
||||||
|
err: nil,
|
||||||
|
opts: control.Options{},
|
||||||
|
expect: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty skip on 503",
|
||||||
|
err: nil,
|
||||||
|
opts: control.Options{
|
||||||
|
SkipTheseEventsOnInstance503: map[string][]string{},
|
||||||
|
},
|
||||||
|
expect: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nil error",
|
||||||
|
err: nil,
|
||||||
|
opts: control.Options{
|
||||||
|
SkipTheseEventsOnInstance503: map[string][]string{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expect: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-matching resource",
|
||||||
|
err: clues.New("fix me I'm wrong"),
|
||||||
|
opts: control.Options{
|
||||||
|
SkipTheseEventsOnInstance503: map[string][]string{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expect: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-matching item",
|
||||||
|
err: clues.New("fix me I'm wrong"),
|
||||||
|
opts: control.Options{
|
||||||
|
SkipTheseEventsOnInstance503: map[string][]string{
|
||||||
|
resourceID: []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expect: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "match on instance 503",
|
||||||
|
err: clues.New("fix me I'm wrong"),
|
||||||
|
opts: control.Options{
|
||||||
|
SkipTheseEventsOnInstance503: map[string][]string{
|
||||||
|
resourceID: []string{"bar", itemID},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expect: assert.True,
|
||||||
|
expectCause: fault.SkipKnownEventInstance503s,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.Run(test.name, func() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
h := newEventBackupHandler(api.Client{})
|
||||||
|
cause, result := h.CanSkipItemFailure(
|
||||||
|
test.err,
|
||||||
|
resourceID,
|
||||||
|
itemID,
|
||||||
|
test.opts)
|
||||||
|
|
||||||
|
test.expect(t, result)
|
||||||
|
assert.Equal(t, test.expectCause, cause)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,6 +26,8 @@ type backupHandler interface {
|
|||||||
previewIncludeContainers() []string
|
previewIncludeContainers() []string
|
||||||
previewExcludeContainers() []string
|
previewExcludeContainers() []string
|
||||||
NewContainerCache(userID string) (string, graph.ContainerResolver)
|
NewContainerCache(userID string) (string, graph.ContainerResolver)
|
||||||
|
|
||||||
|
canSkipItemFailurer
|
||||||
}
|
}
|
||||||
|
|
||||||
type addedAndRemovedItemGetter interface {
|
type addedAndRemovedItemGetter interface {
|
||||||
@ -57,6 +59,14 @@ func BackupHandlers(ac api.Client) map[path.CategoryType]backupHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type canSkipItemFailurer interface {
|
||||||
|
CanSkipItemFailure(
|
||||||
|
err error,
|
||||||
|
resourceID, itemID string,
|
||||||
|
opts control.Options,
|
||||||
|
) (fault.SkipCause, bool)
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// restore
|
// restore
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package exchange
|
package exchange
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
|
||||||
)
|
)
|
||||||
@ -57,3 +59,11 @@ func (h mailBackupHandler) NewContainerCache(
|
|||||||
getter: h.ac,
|
getter: h.ac,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h mailBackupHandler) CanSkipItemFailure(
|
||||||
|
error,
|
||||||
|
string, string,
|
||||||
|
control.Options,
|
||||||
|
) (fault.SkipCause, bool) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|||||||
31
src/internal/m365/collection/exchange/mail_backup_test.go
Normal file
31
src/internal/m365/collection/exchange/mail_backup_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MailBackupHandlerUnitSuite struct {
|
||||||
|
tester.Suite
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMailBackupHandlerUnitSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &MailBackupHandlerUnitSuite{Suite: tester.NewUnitSuite(t)})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MailBackupHandlerUnitSuite) TestHandler_CanSkipItemFailure() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
h := newMailBackupHandler(api.Client{})
|
||||||
|
cause, result := h.CanSkipItemFailure(nil, "", "", control.Options{})
|
||||||
|
|
||||||
|
assert.False(t, result)
|
||||||
|
assert.Equal(t, fault.SkipCause(""), cause)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user