add clues/fault to exchange restore (#2491)

## Does this PR need a docs update or release note?

- [ ]  No 

## Type of change

- [x] 🧹 Tech Debt/Cleanup

## Issue(s)

* #1970

## Test Plan

- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2023-02-14 12:33:07 -07:00 committed by GitHub
parent 31c9195a12
commit 570ce85656
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 172 additions and 154 deletions

View File

@ -53,6 +53,7 @@ func generateAndRestoreItems(
howMany int,
dbf dataBuilderFunc,
opts control.Options,
errs *fault.Errors,
) (*details.Details, error) {
items := make([]item, 0, howMany)
@ -93,7 +94,7 @@ func generateAndRestoreItems(
Infof(ctx, "Generating %d %s items in %s\n", howMany, cat, Destination)
return gc.RestoreDataCollections(ctx, backup.Version, acct, sel, dest, opts, dataColls)
return gc.RestoreDataCollections(ctx, backup.Version, acct, sel, dest, opts, dataColls, errs)
}
// ------------------------------------------------------------------------------------------

View File

@ -1,12 +1,15 @@
package impl
import (
"github.com/alcionai/clues"
"github.com/spf13/cobra"
. "github.com/alcionai/corso/src/cli/print"
"github.com/alcionai/corso/src/cli/utils"
"github.com/alcionai/corso/src/internal/connector/mockconnector"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
)
@ -42,6 +45,7 @@ func handleExchangeEmailFactory(cmd *cobra.Command, args []string) error {
ctx = cmd.Context()
service = path.ExchangeService
category = path.EmailCategory
errs = fault.New(false)
)
if utils.HasNoFlagsAndShownHelp(cmd) {
@ -69,11 +73,16 @@ func handleExchangeEmailFactory(cmd *cobra.Command, args []string) error {
now, now, now, now)
},
control.Options{},
)
errs)
if err != nil {
return Only(ctx, err)
}
log := logger.Ctx(ctx)
for _, e := range errs.Errs() {
log.Errorw(e.Error(), clues.InErr(err).Slice()...)
}
deets.PrintEntries(ctx)
return nil
@ -84,6 +93,7 @@ func handleExchangeCalendarEventFactory(cmd *cobra.Command, args []string) error
ctx = cmd.Context()
service = path.ExchangeService
category = path.EventsCategory
errs = fault.New(false)
)
if utils.HasNoFlagsAndShownHelp(cmd) {
@ -110,11 +120,16 @@ func handleExchangeCalendarEventFactory(cmd *cobra.Command, args []string) error
now, now, false)
},
control.Options{},
)
errs)
if err != nil {
return Only(ctx, err)
}
log := logger.Ctx(ctx)
for _, e := range errs.Errs() {
log.Errorw(e.Error(), clues.InErr(err).Slice()...)
}
deets.PrintEntries(ctx)
return nil
@ -125,6 +140,7 @@ func handleExchangeContactFactory(cmd *cobra.Command, args []string) error {
ctx = cmd.Context()
service = path.ExchangeService
category = path.ContactsCategory
errs = fault.New(false)
)
if utils.HasNoFlagsAndShownHelp(cmd) {
@ -156,11 +172,16 @@ func handleExchangeContactFactory(cmd *cobra.Command, args []string) error {
)
},
control.Options{},
)
errs)
if err != nil {
return Only(ctx, err)
}
log := logger.Ctx(ctx)
for _, e := range errs.Errs() {
log.Errorw(e.Error(), clues.InErr(err).Slice()...)
}
deets.PrintEntries(ctx)
return nil

View File

@ -243,6 +243,7 @@ func (gc *GraphConnector) RestoreDataCollections(
dest control.RestoreDestination,
opts control.Options,
dcs []data.RestoreCollection,
errs *fault.Errors,
) (*details.Details, error) {
ctx, end := D.Span(ctx, "connector:restore")
defer end()
@ -260,7 +261,7 @@ func (gc *GraphConnector) RestoreDataCollections(
switch selector.Service {
case selectors.ServiceExchange:
status, err = exchange.RestoreExchangeDataCollections(ctx, creds, gc.Service, dest, dcs, deets)
status, err = exchange.RestoreExchangeDataCollections(ctx, creds, gc.Service, dest, dcs, deets, errs)
case selectors.ServiceOneDrive:
status, err = onedrive.RestoreCollections(ctx, backupVersion, gc.Service, dest, opts, dcs, deets)
case selectors.ServiceSharePoint:

View File

@ -8,6 +8,7 @@ import (
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/pkg/errors"
"github.com/alcionai/clues"
"github.com/alcionai/corso/src/internal/common/ptr"
"github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/connector/uploadsession"
@ -46,46 +47,42 @@ func uploadAttachment(
uploader attachmentUploadable,
attachment models.Attachmentable,
) error {
logger.Ctx(ctx).Debugf("uploading attachment with size %d", *attachment.GetSize())
attachmentType := attachmentType(attachment)
ctx = clues.AddAll(
ctx,
"attachment_size", ptr.Val(attachment.GetSize()),
"attachment_id", ptr.Val(attachment.GetId()),
"attachment_name", ptr.Val(attachment.GetName()), // TODO: pii
"attachment_type", attachmentType,
"internal_item_type", getItemAttachmentItemType(attachment),
"uploader_item_id", uploader.getItemID())
logger.Ctx(ctx).Debugw("uploading attachment")
var (
attachmentType = attachmentType(attachment)
err error
)
// Reference attachments that are inline() do not need to be recreated. The contents are part of the body.
if attachmentType == models.REFERENCE_ATTACHMENTTYPE &&
attachment.GetIsInline() != nil && *attachment.GetIsInline() {
logger.Ctx(ctx).Debugf("skip uploading inline reference attachment: ", *attachment.GetName())
if attachmentType == models.REFERENCE_ATTACHMENTTYPE && ptr.Val(attachment.GetIsInline()) {
logger.Ctx(ctx).Debug("skip uploading inline reference attachment: ", ptr.Val(attachment.GetName()))
return nil
}
// item Attachments to be skipped until the completion of Issue #2353
if attachmentType == models.ITEM_ATTACHMENTTYPE {
prev := attachment
attachment, err = support.ToItemAttachment(attachment)
a, err := support.ToItemAttachment(attachment)
if err != nil {
name := ptr.Val(prev.GetName())
msg := "item attachment restore not supported for this type. skipping upload."
// TODO: (rkeepers) Update to support PII protection
logger.Ctx(ctx).Infow(msg,
"err", err,
"attachment_name", name,
"attachment_type", attachmentType,
"internal_item_type", getItemAttachmentItemType(prev),
"attachment_id", ptr.Val(prev.GetId()),
)
logger.Ctx(ctx).
With("err", err).
Infow("item attachment restore not supported for this type. skipping upload.", clues.InErr(err).Slice()...)
return nil
}
attachment = a
}
// For Item/Reference attachments *or* file attachments < 3MB, use the attachments endpoint
if attachmentType != models.FILE_ATTACHMENTTYPE || *attachment.GetSize() < largeAttachmentSize {
err := uploader.uploadSmallAttachment(ctx, attachment)
return err
if attachmentType != models.FILE_ATTACHMENTTYPE || ptr.Val(attachment.GetSize()) < largeAttachmentSize {
return uploader.uploadSmallAttachment(ctx, attachment)
}
return uploadLargeAttachment(ctx, uploader, attachment)
@ -93,7 +90,9 @@ func uploadAttachment(
// uploadLargeAttachment will upload the specified attachment by creating an upload session and
// doing a chunked upload
func uploadLargeAttachment(ctx context.Context, uploader attachmentUploadable,
func uploadLargeAttachment(
ctx context.Context,
uploader attachmentUploadable,
attachment models.Attachmentable,
) error {
ab := attachmentBytes(attachment)

View File

@ -3,12 +3,11 @@ package exchange
import (
"context"
"github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models"
msusers "github.com/microsoftgraph/msgraph-sdk-go/users"
"github.com/pkg/errors"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/internal/connector/support"
)
// attachementUploadable represents structs that are able to upload small attachments directly to an item or use an
@ -45,7 +44,7 @@ func (mau *mailAttachmentUploader) uploadSmallAttachment(ctx context.Context, at
Attachments().
Post(ctx, attach, nil)
if err != nil {
return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
return clues.Stack(err).WithClues(ctx).WithAll(graph.ErrData(err)...)
}
return nil
@ -69,12 +68,7 @@ func (mau *mailAttachmentUploader) uploadSession(
CreateUploadSession().
Post(ctx, session, nil)
if err != nil {
return nil, errors.Wrapf(
err,
"failed to create attachment upload session for item %s. details: %s",
mau.itemID,
support.ConnectorStackErrorTrace(err),
)
return nil, clues.Wrap(err, "uploading mail attachment").WithClues(ctx).WithAll(graph.ErrData(err)...)
}
return r, nil
@ -100,7 +94,7 @@ func (eau *eventAttachmentUploader) uploadSmallAttachment(ctx context.Context, a
Attachments().
Post(ctx, attach, nil)
if err != nil {
return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
return clues.Stack(err).WithClues(ctx).WithAll(graph.ErrData(err)...)
}
return nil
@ -122,11 +116,7 @@ func (eau *eventAttachmentUploader) uploadSession(
CreateUploadSession().
Post(ctx, session, nil)
if err != nil {
return nil, errors.Wrapf(
err,
"failed to create attachment upload session for event item %s. details: %s",
eau.itemID, support.ConnectorStackErrorTrace(err),
)
return nil, clues.Wrap(err, "uploading event attachment").WithClues(ctx).WithAll(graph.ErrData(err)...)
}
return r, nil

View File

@ -17,6 +17,7 @@ import (
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/path"
)
@ -119,7 +120,8 @@ func (suite *ExchangeRestoreSuite) TestRestoreEvent() {
suite.gs,
control.Copy,
calendarID,
userID)
userID,
fault.New(true))
assert.NoError(t, err, support.ConnectorStackErrorTrace(err))
assert.NotNil(t, info, "event item info")
}
@ -346,7 +348,7 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
service,
destination,
userID,
)
fault.New(true))
assert.NoError(t, err, support.ConnectorStackErrorTrace(err))
assert.NotNil(t, info, "item info was not populated")
assert.NotNil(t, deleters)

View File

@ -7,6 +7,7 @@ import (
"reflect"
"runtime/trace"
"github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/pkg/errors"
@ -21,6 +22,7 @@ import (
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path"
)
@ -35,20 +37,21 @@ func RestoreExchangeObject(
policy control.CollisionPolicy,
service graph.Servicer,
destination, user string,
errs *fault.Errors,
) (*details.ExchangeInfo, error) {
if policy != control.Copy {
return nil, fmt.Errorf("restore policy: %s not supported for RestoreExchangeObject", policy)
return nil, clues.Wrap(clues.New(policy.String()), "policy not supported for Exchange restore").WithClues(ctx)
}
switch category {
case path.EmailCategory:
return RestoreMailMessage(ctx, bits, service, control.Copy, destination, user)
return RestoreMailMessage(ctx, bits, service, control.Copy, destination, user, errs)
case path.ContactsCategory:
return RestoreExchangeContact(ctx, bits, service, control.Copy, destination, user)
case path.EventsCategory:
return RestoreExchangeEvent(ctx, bits, service, control.Copy, destination, user)
return RestoreExchangeEvent(ctx, bits, service, control.Copy, destination, user, errs)
default:
return nil, fmt.Errorf("type: %s not supported for RestoreExchangeObject", category)
return nil, clues.Wrap(clues.New(category.String()), "not supported for Exchange restore")
}
}
@ -67,22 +70,18 @@ func RestoreExchangeContact(
) (*details.ExchangeInfo, error) {
contact, err := support.CreateContactFromBytes(bits)
if err != nil {
return nil, errors.Wrap(err, "creating contact from bytes: RestoreExchangeContact")
return nil, clues.Wrap(err, "creating contact from bytes").WithClues(ctx)
}
ctx = clues.Add(ctx, "item_id", ptr.Val(contact.GetId()))
response, err := service.Client().UsersById(user).ContactFoldersById(destination).Contacts().Post(ctx, contact, nil)
if err != nil {
name := ptr.Val(contact.GetGivenName())
return nil, errors.Wrap(
err,
"uploading Contact during RestoreExchangeContact: "+name+" "+
support.ConnectorStackErrorTrace(err),
)
return nil, clues.Wrap(err, "uploading Contact").WithClues(ctx).WithAll(graph.ErrData(err)...)
}
if response == nil {
return nil, errors.New("msgraph contact post fail: REST response not received")
return nil, clues.New("nil response from post").WithClues(ctx)
}
info := api.ContactInfo(contact)
@ -103,17 +102,18 @@ func RestoreExchangeEvent(
service graph.Servicer,
cp control.CollisionPolicy,
destination, user string,
errs *fault.Errors,
) (*details.ExchangeInfo, error) {
event, err := support.CreateEventFromBytes(bits)
if err != nil {
return nil, errors.Wrap(err, "creating event from bytes: RestoreExchangeEvent")
return nil, clues.Wrap(err, "creating event from bytes").WithClues(ctx)
}
transformedEvent := support.ToEventSimplified(event)
ctx = clues.Add(ctx, "item_id", ptr.Val(event.GetId()))
var (
attached []models.Attachmentable
errs error
transformedEvent = support.ToEventSimplified(event)
attached []models.Attachmentable
)
if *event.GetHasAttachments() {
@ -124,15 +124,11 @@ func RestoreExchangeEvent(
response, err := service.Client().UsersById(user).CalendarsById(destination).Events().Post(ctx, transformedEvent, nil)
if err != nil {
return nil, errors.Wrap(err,
fmt.Sprintf(
"uploading event during RestoreExchangeEvent: %s",
support.ConnectorStackErrorTrace(err)),
)
return nil, clues.Wrap(err, "uploading event").WithClues(ctx).WithAll(graph.ErrData(err)...)
}
if response == nil {
return nil, errors.New("msgraph event post fail: REST response not received")
return nil, clues.New("nil response from post").WithClues(ctx)
}
uploader := &eventAttachmentUploader{
@ -143,25 +139,19 @@ func RestoreExchangeEvent(
}
for _, attach := range attached {
if err := uploadAttachment(ctx, uploader, attach); err != nil {
errs = support.WrapAndAppend(
fmt.Sprintf(
"uploading attachment for message %s: %s",
ptr.Val(transformedEvent.GetId()),
support.ConnectorStackErrorTrace(err),
),
err,
errs,
)
if errs.Err() != nil {
break
}
if err := uploadAttachment(ctx, uploader, attach); err != nil {
errs.Add(err)
}
}
info := api.EventInfo(event)
info.Size = int64(len(bits))
return info, errs
return info, errs.Err()
}
// RestoreMailMessage utility function to place an exchange.Mail
@ -176,16 +166,21 @@ func RestoreMailMessage(
service graph.Servicer,
cp control.CollisionPolicy,
destination, user string,
errs *fault.Errors,
) (*details.ExchangeInfo, error) {
// Creates messageable object from original bytes
originalMessage, err := support.CreateMessageFromBytes(bits)
if err != nil {
return nil, errors.Wrap(err, "creating email from bytes: RestoreMailMessage")
return nil, clues.Wrap(err, "creating mail from bytes").WithClues(ctx)
}
// Sets fields from original message from storage
clone := support.ToMessage(originalMessage)
valueID := MailRestorePropertyTag
enableValue := RestoreCanonicalEnableValue
ctx = clues.Add(ctx, "item_id", ptr.Val(originalMessage.GetId()))
var (
clone = support.ToMessage(originalMessage)
valueID = MailRestorePropertyTag
enableValue = RestoreCanonicalEnableValue
)
// Set Extended Properties:
// 1st: No transmission
@ -219,17 +214,8 @@ func RestoreMailMessage(
clone.SetSingleValueExtendedProperties(svlep)
// Switch workflow based on collision policy
switch cp {
default:
logger.Ctx(ctx).DPanicw("restoreMailMessage received unrecognized restore policy; defaulting to copy",
"policy", cp)
fallthrough
case control.Copy:
err := SendMailToBackStore(ctx, service, user, destination, clone)
if err != nil {
return nil, err
}
if err := SendMailToBackStore(ctx, service, user, destination, clone, errs); err != nil {
return nil, err
}
info := api.MailInfo(clone)
@ -253,28 +239,23 @@ func SendMailToBackStore(
service graph.Servicer,
user, destination string,
message models.Messageable,
errs *fault.Errors,
) error {
var (
attached []models.Attachmentable
errs error
)
attached := message.GetAttachments()
// Item.Attachments --> HasAttachments doesn't always have a value populated when deserialized
attached = message.GetAttachments()
message.SetAttachments([]models.Attachmentable{})
sentMessage, err := service.Client().UsersById(user).MailFoldersById(destination).Messages().Post(ctx, message, nil)
response, err := service.Client().UsersById(user).MailFoldersById(destination).Messages().Post(ctx, message, nil)
if err != nil {
return errors.Wrap(err,
user+": failure sendMailAPI: Dest: "+destination+" Details: "+support.ConnectorStackErrorTrace(err),
)
return clues.Wrap(err, "restoring mail").WithClues(ctx).WithAll(graph.ErrData(err)...)
}
if sentMessage == nil {
return errors.New("message not Sent: blocked by server")
if response == nil {
return clues.New("nil response from post").WithClues(ctx)
}
id := *sentMessage.GetId()
id := ptr.Val(response.GetId())
uploader := &mailAttachmentUploader{
userID: user,
@ -284,29 +265,28 @@ func SendMailToBackStore(
}
for _, attachment := range attached {
if errs.Err() != nil {
break
}
if err := uploadAttachment(ctx, uploader, attachment); err != nil {
if ptr.Val(attachment.GetOdataType()) == "#microsoft.graph.itemAttachment" {
name := ptr.Val(attachment.GetName())
logger.Ctx(ctx).Infow(
"item attachment upload not successful. content not accepted by M365 server",
"Attachment Name", name)
logger.Ctx(ctx).
With("err", err, "attachment_name", name).
Infow("mail upload failed", clues.InErr(err).Slice()...)
continue
}
errs = support.WrapAndAppend(
fmt.Sprintf("uploading attachment for message %s: %s",
id, support.ConnectorStackErrorTrace(err)),
err,
errs,
)
errs.Add(errors.Wrap(err, "uploading mail attachment"))
break
}
}
return errs
return errs.Err()
}
// RestoreExchangeDataCollections restores M365 objects in data.RestoreCollection to MSFT
@ -319,22 +299,25 @@ func RestoreExchangeDataCollections(
dest control.RestoreDestination,
dcs []data.RestoreCollection,
deets *details.Builder,
errs *fault.Errors,
) (*support.ConnectorOperationStatus, error) {
var (
// map of caches... but not yet...
directoryCaches = make(map[string]map[path.CategoryType]graph.ContainerResolver)
metrics support.CollectionMetrics
errs error
userID string
// TODO policy to be updated from external source after completion of refactoring
policy = control.Copy
)
errUpdater := func(id string, err error) {
errs = support.WrapAndAppend(id, err, errs)
if len(dcs) > 0 {
userID = dcs[0].FullPath().ResourceOwner()
ctx = clues.Add(ctx, "resource_owner", userID) // TODO: pii
}
for _, dc := range dcs {
userID := dc.FullPath().ResourceOwner()
if errs.Err() != nil {
return nil, errs.Err()
}
userCaches := directoryCaches[userID]
if userCaches == nil {
@ -349,11 +332,11 @@ func RestoreExchangeDataCollections(
dest.ContainerName,
userCaches)
if err != nil {
errs = support.WrapAndAppend(dc.FullPath().ShortRef(), err, errs)
errs.Add(clues.Wrap(err, "creating destination").WithClues(ctx))
continue
}
temp, canceled := restoreCollection(ctx, gs, dc, containerID, policy, deets, errUpdater)
temp, canceled := restoreCollection(ctx, gs, dc, containerID, policy, deets, errs)
metrics.Combine(temp)
@ -362,14 +345,15 @@ func RestoreExchangeDataCollections(
}
}
status := support.CreateStatus(ctx,
status := support.CreateStatus(
ctx,
support.Restore,
len(dcs),
metrics,
errs,
errs.Err(),
dest.ContainerName)
return status, errs
return status, errs.Err()
}
// restoreCollection handles restoration of an individual collection.
@ -380,7 +364,7 @@ func restoreCollection(
folderID string,
policy control.CollisionPolicy,
deets *details.Builder,
errUpdater func(string, error),
errs *fault.Errors,
) (support.CollectionMetrics, bool) {
ctx, end := D.Span(ctx, "gc:exchange:restoreCollection", D.Label("path", dc.FullPath()))
defer end()
@ -394,6 +378,12 @@ func restoreCollection(
user = directory.ResourceOwner()
)
ctx = clues.AddAll(
ctx,
"full_path", directory,
"service", service,
"category", category)
colProgress, closer := observe.CollectionProgress(
ctx,
category.String(),
@ -405,34 +395,39 @@ func restoreCollection(
for {
select {
case <-ctx.Done():
errUpdater("context cancelled", ctx.Err())
errs.Add(clues.Wrap(ctx.Err(), "context cancelled").WithClues(ctx))
return metrics, true
case itemData, ok := <-items:
if !ok {
if !ok || errs.Err() != nil {
return metrics, false
}
metrics.Objects++
trace.Log(ctx, "gc:exchange:restoreCollection:item", itemData.UUID())
ictx := clues.Add(ctx, "item_id", itemData.UUID())
trace.Log(ictx, "gc:exchange:restoreCollection:item", itemData.UUID())
metrics.Objects++
buf := &bytes.Buffer{}
_, err := buf.ReadFrom(itemData.ToReader())
if err != nil {
errUpdater(itemData.UUID()+": byteReadError during RestoreDataCollection", err)
errs.Add(clues.Wrap(err, "reading item bytes").WithClues(ictx))
continue
}
byteArray := buf.Bytes()
info, err := RestoreExchangeObject(ctx, byteArray, category, policy, gs, folderID, user)
info, err := RestoreExchangeObject(
ictx,
byteArray,
category,
policy,
gs,
folderID,
user,
errs)
if err != nil {
// More information to be here
errUpdater(
itemData.UUID()+": failed to upload RestoreExchangeObject: "+service.String()+"-"+category.String(),
err)
errs.Add(err)
continue
}
@ -441,7 +436,7 @@ func restoreCollection(
itemPath, err := dc.FullPath().Append(itemData.UUID(), true)
if err != nil {
logger.Ctx(ctx).DPanicw("transforming item to full path", "error", err)
errs.Add(clues.Wrap(err, "building full path with item").WithClues(ctx))
continue
}
@ -487,7 +482,7 @@ func CreateContainerDestination(
// TODO(rkeepers): pass the api client into this func, rather than generating one.
ac, err := api.NewClient(creds)
if err != nil {
return "", err
return "", clues.Stack(err).WithClues(ctx)
}
switch category {
@ -569,7 +564,7 @@ func CreateContainerDestination(
newCache)
default:
return "", fmt.Errorf("category: %s not support for exchange cache", category)
return "", clues.Wrap(fmt.Errorf("%T", category), "not support for exchange cache").WithClues(ctx)
}
}
@ -591,6 +586,8 @@ func establishMailRestoreLocation(
folderID := rootFolderAlias
pb := path.Builder{}
ctx = clues.Add(ctx, "is_new_cache", isNewCache)
for _, folder := range folders {
pb = *pb.Append(folder)
@ -647,6 +644,8 @@ func establishContactsRestoreLocation(
return cached, nil
}
ctx = clues.Add(ctx, "is_new_cache", isNewCache)
temp, err := ac.Contacts().CreateContactFolder(ctx, user, folders[0])
if err != nil {
return "", errors.Wrap(err, support.ConnectorStackErrorTrace(err))
@ -681,6 +680,8 @@ func establishEventsRestoreLocation(
return cached, nil
}
ctx = clues.Add(ctx, "is_new_cache", isNewCache)
temp, err := ac.Events().CreateCalendar(ctx, user, folders[0])
if err != nil {
return "", errors.Wrap(err, support.ConnectorStackErrorTrace(err))

View File

@ -250,7 +250,7 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreFailsBadService() {
ToggleFeatures: control.Toggles{EnablePermissionsBackup: true},
},
nil,
)
fault.New(true))
assert.Error(t, err)
assert.NotNil(t, deets)
@ -327,7 +327,7 @@ func (suite *GraphConnectorIntegrationSuite) TestEmptyCollections() {
ToggleFeatures: control.Toggles{EnablePermissionsBackup: true},
},
test.col,
)
fault.New(true))
require.NoError(t, err)
assert.NotNil(t, deets)
@ -422,7 +422,7 @@ func runRestoreBackupTest(
dest,
opts,
collections,
)
fault.New(true))
require.NoError(t, err)
assert.NotNil(t, deets)
@ -544,7 +544,7 @@ func runRestoreBackupTestVersion0(
dest,
opts,
collections,
)
fault.New(true))
require.NoError(t, err)
assert.NotNil(t, deets)
@ -1515,7 +1515,7 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames
ToggleFeatures: control.Toggles{EnablePermissionsBackup: true},
},
collections,
)
fault.New(true))
require.NoError(t, err)
require.NotNil(t, deets)

View File

@ -63,6 +63,7 @@ func CreateStatus(
}
hasErrors := err != nil
// TODO(keeprs): remove
numErr := GetNumberOfErrors(err)
status := ConnectorOperationStatus{

View File

@ -347,7 +347,8 @@ func generateContainerOfItems(
sel,
dest,
control.Options{RestorePermissions: true},
dataColls)
dataColls,
fault.New(true))
require.NoError(t, err)
return deets

View File

@ -258,7 +258,8 @@ func (op *RestoreOperation) do(
op.Selectors,
op.Destination,
op.Options,
dcs)
dcs,
op.Errors)
if err != nil {
return nil, errors.Wrap(err, "restoring collections")
}