diff --git a/src/cli/backup/exchange.go b/src/cli/backup/exchange.go index ac6455522..1f6f6ae81 100644 --- a/src/cli/backup/exchange.go +++ b/src/cli/backup/exchange.go @@ -16,6 +16,7 @@ import ( "github.com/alcionai/corso/src/internal/model" "github.com/alcionai/corso/src/pkg/backup" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/repository" "github.com/alcionai/corso/src/pkg/selectors" @@ -470,9 +471,10 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error { defer utils.CloseRepo(ctx, r) - ds, err := runDetailsExchangeCmd(ctx, r, backupID, opts) - if err != nil { - return Only(ctx, err) + ds, errs := runDetailsExchangeCmd(ctx, r, backupID, opts) + if errs.Err() != nil { + // TODO: log/display iterated errors + return Only(ctx, errs.Err()) } if len(ds.Entries) == 0 { @@ -486,29 +488,33 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error { } // runDetailsExchangeCmd actually performs the lookup in backup details. +// the fault.Errors return is always non-nil. Callers should check if +// errs.Err() == nil. func runDetailsExchangeCmd( ctx context.Context, r repository.BackupGetter, backupID string, opts utils.ExchangeOpts, -) (*details.Details, error) { +) (*details.Details, *fault.Errors) { + errs := fault.New(false) + if err := utils.ValidateExchangeRestoreFlags(backupID, opts); err != nil { - return nil, err + return nil, errs.Fail(err) } d, _, err := r.BackupDetails(ctx, backupID) if err != nil { if errors.Is(err, kopia.ErrNotFound) { - return nil, errors.Errorf("No backup exists with the id %s", backupID) + return nil, errs.Fail(errors.Errorf("No backup exists with the id %s", backupID)) } - return nil, errors.Wrap(err, "Failed to get backup details in the repository") + return nil, errs.Fail(errors.Wrap(err, "Failed to get backup details in the repository")) } sel := utils.IncludeExchangeRestoreDataSelectors(opts) utils.FilterExchangeRestoreInfoSelectors(sel, opts) - return sel.Reduce(ctx, d), nil + return sel.Reduce(ctx, d, errs), errs } // ------------------------------------------------------------------------------------------------ diff --git a/src/cli/backup/exchange_test.go b/src/cli/backup/exchange_test.go index ecb7bec29..c67a5c15b 100644 --- a/src/cli/backup/exchange_test.go +++ b/src/cli/backup/exchange_test.go @@ -223,33 +223,14 @@ func (suite *ExchangeSuite) TestExchangeBackupDetailsSelectors() { ctx, test.BackupGetter, "backup-ID", - test.Opts, - ) - assert.NoError(t, err) - + test.Opts) + assert.NoError(t, err.Err(), "failure") + assert.Empty(t, err.Errs(), "recovered errors") assert.ElementsMatch(t, test.Expected, output.Entries) }) } } -func (suite *ExchangeSuite) TestExchangeBackupDetailsSelectorsBadBackupID() { - t := suite.T() - ctx, flush := tester.NewContext() - backupGetter := &testdata.MockBackupGetter{} - - defer flush() - - output, err := runDetailsExchangeCmd( - ctx, - backupGetter, - "backup-ID", - utils.ExchangeOpts{}, - ) - assert.Error(t, err) - - assert.Empty(t, output) -} - func (suite *ExchangeSuite) TestExchangeBackupDetailsSelectorsBadFormats() { ctx, flush := tester.NewContext() defer flush() @@ -260,10 +241,9 @@ func (suite *ExchangeSuite) TestExchangeBackupDetailsSelectorsBadFormats() { ctx, test.BackupGetter, "backup-ID", - test.Opts, - ) - - assert.Error(t, err) + test.Opts) + assert.Error(t, err.Err(), "failure") + assert.Empty(t, err.Errs(), "recovered errors") assert.Empty(t, output) }) } diff --git a/src/cli/backup/onedrive.go b/src/cli/backup/onedrive.go index 9dfb20b79..517477661 100644 --- a/src/cli/backup/onedrive.go +++ b/src/cli/backup/onedrive.go @@ -16,6 +16,7 @@ import ( "github.com/alcionai/corso/src/internal/model" "github.com/alcionai/corso/src/pkg/backup" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/repository" "github.com/alcionai/corso/src/pkg/selectors" @@ -362,9 +363,10 @@ func detailsOneDriveCmd(cmd *cobra.Command, args []string) error { Populated: utils.GetPopulatedFlags(cmd), } - ds, err := runDetailsOneDriveCmd(ctx, r, backupID, opts) - if err != nil { - return Only(ctx, err) + ds, errs := runDetailsOneDriveCmd(ctx, r, backupID, opts) + if errs.Err() != nil { + // TODO: log/display iterated errors + return Only(ctx, errs.Err()) } if len(ds.Entries) == 0 { @@ -378,29 +380,33 @@ func detailsOneDriveCmd(cmd *cobra.Command, args []string) error { } // runDetailsOneDriveCmd actually performs the lookup in backup details. +// the fault.Errors return is always non-nil. Callers should check if +// errs.Err() == nil. func runDetailsOneDriveCmd( ctx context.Context, r repository.BackupGetter, backupID string, opts utils.OneDriveOpts, -) (*details.Details, error) { +) (*details.Details, *fault.Errors) { + errs := fault.New(false) + if err := utils.ValidateOneDriveRestoreFlags(backupID, opts); err != nil { - return nil, err + return nil, errs.Fail(err) } d, _, err := r.BackupDetails(ctx, backupID) if err != nil { if errors.Is(err, kopia.ErrNotFound) { - return nil, errors.Errorf("no backup exists with the id %s", backupID) + return nil, errs.Fail(errors.Errorf("no backup exists with the id %s", backupID)) } - return nil, errors.Wrap(err, "Failed to get backup details in the repository") + return nil, errs.Fail(errors.Wrap(err, "Failed to get backup details in the repository")) } sel := utils.IncludeOneDriveRestoreDataSelectors(opts) utils.FilterOneDriveRestoreInfoSelectors(sel, opts) - return sel.Reduce(ctx, d), nil + return sel.Reduce(ctx, d, errs), errs } // `corso backup delete onedrive [...]` diff --git a/src/cli/backup/onedrive_test.go b/src/cli/backup/onedrive_test.go index 2f7654969..7fb2a38e3 100644 --- a/src/cli/backup/onedrive_test.go +++ b/src/cli/backup/onedrive_test.go @@ -98,10 +98,9 @@ func (suite *OneDriveSuite) TestOneDriveBackupDetailsSelectors() { ctx, test.BackupGetter, "backup-ID", - test.Opts, - ) - assert.NoError(t, err) - + test.Opts) + assert.NoError(t, err.Err()) + assert.Empty(t, err.Errs()) assert.ElementsMatch(t, test.Expected, output.Entries) }) } @@ -117,10 +116,9 @@ func (suite *OneDriveSuite) TestOneDriveBackupDetailsSelectorsBadFormats() { ctx, test.BackupGetter, "backup-ID", - test.Opts, - ) - - assert.Error(t, err) + test.Opts) + assert.Error(t, err.Err()) + assert.Empty(t, err.Errs()) assert.Empty(t, output) }) } diff --git a/src/cli/backup/sharepoint.go b/src/cli/backup/sharepoint.go index 45d885b80..e8d65752a 100644 --- a/src/cli/backup/sharepoint.go +++ b/src/cli/backup/sharepoint.go @@ -18,6 +18,7 @@ import ( "github.com/alcionai/corso/src/internal/model" "github.com/alcionai/corso/src/pkg/backup" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/repository" "github.com/alcionai/corso/src/pkg/selectors" @@ -481,9 +482,10 @@ func detailsSharePointCmd(cmd *cobra.Command, args []string) error { Populated: utils.GetPopulatedFlags(cmd), } - ds, err := runDetailsSharePointCmd(ctx, r, backupID, opts) - if err != nil { - return Only(ctx, err) + ds, errs := runDetailsSharePointCmd(ctx, r, backupID, opts) + if errs.Err() != nil { + // TODO: log/display iterated errors + return Only(ctx, errs.Err()) } if len(ds.Entries) == 0 { @@ -497,27 +499,31 @@ func detailsSharePointCmd(cmd *cobra.Command, args []string) error { } // runDetailsSharePointCmd actually performs the lookup in backup details. +// the fault.Errors return is always non-nil. Callers should check if +// errs.Err() == nil. func runDetailsSharePointCmd( ctx context.Context, r repository.BackupGetter, backupID string, opts utils.SharePointOpts, -) (*details.Details, error) { +) (*details.Details, *fault.Errors) { + errs := fault.New(false) + if err := utils.ValidateSharePointRestoreFlags(backupID, opts); err != nil { - return nil, err + return nil, errs.Fail(err) } d, _, err := r.BackupDetails(ctx, backupID) if err != nil { if errors.Is(err, kopia.ErrNotFound) { - return nil, errors.Errorf("no backup exists with the id %s", backupID) + return nil, errs.Fail(errors.Errorf("no backup exists with the id %s", backupID)) } - return nil, errors.Wrap(err, "Failed to get backup details in the repository") + return nil, errs.Fail(errors.Wrap(err, "Failed to get backup details in the repository")) } sel := utils.IncludeSharePointRestoreDataSelectors(opts) utils.FilterSharePointRestoreInfoSelectors(sel, opts) - return sel.Reduce(ctx, d), nil + return sel.Reduce(ctx, d, errs), errs } diff --git a/src/cli/backup/sharepoint_test.go b/src/cli/backup/sharepoint_test.go index 89e40a9f3..a46deeeff 100644 --- a/src/cli/backup/sharepoint_test.go +++ b/src/cli/backup/sharepoint_test.go @@ -213,10 +213,9 @@ func (suite *SharePointSuite) TestSharePointBackupDetailsSelectors() { ctx, test.BackupGetter, "backup-ID", - test.Opts, - ) - assert.NoError(t, err) - + test.Opts) + assert.NoError(t, err.Err()) + assert.Empty(t, err.Errs()) assert.ElementsMatch(t, test.Expected, output.Entries) }) } @@ -232,10 +231,9 @@ func (suite *SharePointSuite) TestSharePointBackupDetailsSelectorsBadFormats() { ctx, test.BackupGetter, "backup-ID", - test.Opts, - ) - - assert.Error(t, err) + test.Opts) + assert.Error(t, err.Err()) + assert.Empty(t, err.Errs()) assert.Empty(t, output) }) } diff --git a/src/go.mod b/src/go.mod index bf43f6494..0d9792c5d 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 - github.com/alcionai/clues v0.0.0-20230131232239-cee86233b005 + github.com/alcionai/clues v0.0.0-20230202001016-cbda58c9de9e github.com/aws/aws-sdk-go v1.44.192 github.com/aws/aws-xray-sdk-go v1.8.0 github.com/google/uuid v1.3.0 diff --git a/src/go.sum b/src/go.sum index 17d6f25bd..566adbca0 100644 --- a/src/go.sum +++ b/src/go.sum @@ -54,6 +54,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/alcionai/clues v0.0.0-20230131232239-cee86233b005 h1:eTgICcmcydEWG8J+hgnidf0pzujV3Gd2XqmknykZkzA= github.com/alcionai/clues v0.0.0-20230131232239-cee86233b005/go.mod h1:UlAs8jkWIpsOMakiC8NxPgQQVQRdvyf1hYMszlYYLb4= +github.com/alcionai/clues v0.0.0-20230202001016-cbda58c9de9e h1:KMRGDB9lh0wC/WYVmQ28MJ07qiHszCSH2PRwkw2YElM= +github.com/alcionai/clues v0.0.0-20230202001016-cbda58c9de9e/go.mod h1:UlAs8jkWIpsOMakiC8NxPgQQVQRdvyf1hYMszlYYLb4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= diff --git a/src/internal/operations/restore.go b/src/internal/operations/restore.go index 5fd8c9ffb..a87243a9e 100644 --- a/src/internal/operations/restore.go +++ b/src/internal/operations/restore.go @@ -344,7 +344,7 @@ func formatDetailsForRestoration( deets *details.Details, errs *fault.Errors, ) ([]path.Path, error) { - fds, err := sel.Reduce(ctx, deets) + fds, err := sel.Reduce(ctx, deets, errs) if err != nil { return nil, err } diff --git a/src/pkg/selectors/example_selectors_test.go b/src/pkg/selectors/example_selectors_test.go index d802585cc..ff556a306 100644 --- a/src/pkg/selectors/example_selectors_test.go +++ b/src/pkg/selectors/example_selectors_test.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/selectors" ) @@ -52,7 +53,7 @@ func Example_newSelector() { bSel.ToOneDriveBackup() } - // Output: OneDrive service is not Exchange: wrong selector service type + // Output: wrong selector service type: OneDrive is not Exchange } // ExampleIncludeFoldersAndItems demonstrates how to select for granular data. @@ -141,10 +142,11 @@ func Example_reduceDetails() { ser := selectors.NewExchangeRestore( []string{"your-user-id", "foo-user-id", "bar-user-id"}, ) + errAgg := fault.New(false) // The Reduce() call is where our constructed selectors are applied to the data // from a previous backup record. - filteredDetails := ser.Reduce(ctxBG, exampleDetails) + filteredDetails := ser.Reduce(ctxBG, exampleDetails, errAgg) // We haven't added any scopes to our selector yet, so none of the data is retained. fmt.Println("Before adding scopes:", len(filteredDetails.Entries)) @@ -153,7 +155,7 @@ func Example_reduceDetails() { ser.Filter(ser.MailSubject("the answer to life")) // Now that we've selected our data, we should find a result. - filteredDetails = ser.Reduce(ctxBG, exampleDetails) + filteredDetails = ser.Reduce(ctxBG, exampleDetails, errAgg) fmt.Println("After adding scopes:", len(filteredDetails.Entries)) // Output: Before adding scopes: 0 diff --git a/src/pkg/selectors/exchange.go b/src/pkg/selectors/exchange.go index fd3a29e65..a5547749f 100644 --- a/src/pkg/selectors/exchange.go +++ b/src/pkg/selectors/exchange.go @@ -6,6 +6,7 @@ import ( "github.com/alcionai/corso/src/internal/common" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/filters" "github.com/alcionai/corso/src/pkg/path" ) @@ -704,7 +705,11 @@ func (s ExchangeScope) setDefaults() { // Reduce filters the entries in a details struct to only those that match the // inclusions, filters, and exclusions in the selector. -func (s exchange) Reduce(ctx context.Context, deets *details.Details) *details.Details { +func (s exchange) Reduce( + ctx context.Context, + deets *details.Details, + errs fault.Adder, +) *details.Details { return reduce[ExchangeScope]( ctx, deets, @@ -714,7 +719,7 @@ func (s exchange) Reduce(ctx context.Context, deets *details.Details) *details.D path.EventsCategory: ExchangeEvent, path.EmailCategory: ExchangeMail, }, - ) + errs) } // matchesInfo handles the standard behavior when comparing a scope and an ExchangeFilter diff --git a/src/pkg/selectors/exchange_test.go b/src/pkg/selectors/exchange_test.go index df556895f..830cde0c0 100644 --- a/src/pkg/selectors/exchange_test.go +++ b/src/pkg/selectors/exchange_test.go @@ -11,6 +11,7 @@ import ( "github.com/alcionai/corso/src/internal/common" "github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault/mock" "github.com/alcionai/corso/src/pkg/filters" "github.com/alcionai/corso/src/pkg/path" ) @@ -1029,10 +1030,13 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { ctx, flush := tester.NewContext() defer flush() + errs := mock.NewAdder() + sel := test.makeSelector() - results := sel.Reduce(ctx, test.deets) + results := sel.Reduce(ctx, test.deets, errs) paths := results.Paths() assert.Equal(t, test.expect, paths) + assert.Empty(t, errs.Errs) }) } } diff --git a/src/pkg/selectors/onedrive.go b/src/pkg/selectors/onedrive.go index 14ece70fb..f4d924a3b 100644 --- a/src/pkg/selectors/onedrive.go +++ b/src/pkg/selectors/onedrive.go @@ -5,6 +5,7 @@ import ( "github.com/alcionai/corso/src/internal/common" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/filters" "github.com/alcionai/corso/src/pkg/path" ) @@ -483,7 +484,11 @@ func (s OneDriveScope) DiscreteCopy(user string) OneDriveScope { // Reduce filters the entries in a details struct to only those that match the // inclusions, filters, and exclusions in the selector. -func (s oneDrive) Reduce(ctx context.Context, deets *details.Details) *details.Details { +func (s oneDrive) Reduce( + ctx context.Context, + deets *details.Details, + errs fault.Adder, +) *details.Details { return reduce[OneDriveScope]( ctx, deets, @@ -491,7 +496,7 @@ func (s oneDrive) Reduce(ctx context.Context, deets *details.Details) *details.D map[path.CategoryType]oneDriveCategory{ path.FilesCategory: OneDriveItem, }, - ) + errs) } // matchesInfo handles the standard behavior when comparing a scope and an oneDriveInfo diff --git a/src/pkg/selectors/onedrive_test.go b/src/pkg/selectors/onedrive_test.go index 1efcb1f3b..273019519 100644 --- a/src/pkg/selectors/onedrive_test.go +++ b/src/pkg/selectors/onedrive_test.go @@ -11,6 +11,7 @@ import ( "github.com/alcionai/corso/src/internal/common" "github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault/mock" "github.com/alcionai/corso/src/pkg/path" ) @@ -241,10 +242,13 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { ctx, flush := tester.NewContext() defer flush() + errs := mock.NewAdder() + sel := test.makeSelector() - results := sel.Reduce(ctx, test.deets) + results := sel.Reduce(ctx, test.deets, errs) paths := results.Paths() assert.Equal(t, test.expect, paths) + assert.Empty(t, errs.Errs) }) } } diff --git a/src/pkg/selectors/scopes.go b/src/pkg/selectors/scopes.go index 5dc5c4513..9ea595897 100644 --- a/src/pkg/selectors/scopes.go +++ b/src/pkg/selectors/scopes.go @@ -5,10 +5,11 @@ import ( "golang.org/x/exp/maps" + "github.com/alcionai/clues" D "github.com/alcionai/corso/src/internal/diagnostics" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/filters" - "github.com/alcionai/corso/src/pkg/logger" "github.com/alcionai/corso/src/pkg/path" ) @@ -286,6 +287,7 @@ func reduce[T scopeT, C categoryT]( deets *details.Details, s Selector, dataCategories map[path.CategoryType]C, + errs fault.Adder, ) *details.Details { ctx, end := D.Span(ctx, "selectors:reduce") defer end() @@ -311,7 +313,7 @@ func reduce[T scopeT, C categoryT]( for _, ent := range deets.Items() { repoPath, err := path.FromDataLayerPath(ent.RepoRef, true) if err != nil { - logger.Ctx(ctx).Debugw("transforming repoRef to path", "err", err) + errs.Add(clues.Wrap(err, "transforming repoRef to path").WithClues(ctx)) continue } diff --git a/src/pkg/selectors/scopes_test.go b/src/pkg/selectors/scopes_test.go index 9758b1109..848d55767 100644 --- a/src/pkg/selectors/scopes_test.go +++ b/src/pkg/selectors/scopes_test.go @@ -9,6 +9,7 @@ import ( "github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault/mock" "github.com/alcionai/corso/src/pkg/filters" "github.com/alcionai/corso/src/pkg/path" ) @@ -273,13 +274,17 @@ func (suite *SelectorScopesSuite) TestReduce() { ctx, flush := tester.NewContext() defer flush() + errs := mock.NewAdder() + ds := deets() result := reduce[mockScope]( ctx, &ds, test.sel().Selector, - dataCats) + dataCats, + errs) require.NotNil(t, result) + require.Empty(t, errs.Errs, "iteration errors") assert.Len(t, result.Entries, test.expectLen) }) } diff --git a/src/pkg/selectors/selectors.go b/src/pkg/selectors/selectors.go index 505ff1a7b..8a76b8f38 100644 --- a/src/pkg/selectors/selectors.go +++ b/src/pkg/selectors/selectors.go @@ -5,9 +5,11 @@ import ( "encoding/json" "strings" + "github.com/alcionai/clues" "github.com/pkg/errors" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/filters" "github.com/alcionai/corso/src/pkg/path" ) @@ -30,8 +32,9 @@ var serviceToPathType = map[service]path.ServiceType{ } var ( - ErrorBadSelectorCast = errors.New("wrong selector service type") - ErrorNoMatchingItems = errors.New("no items match the specified selectors") + ErrorBadSelectorCast = errors.New("wrong selector service type") + ErrorNoMatchingItems = errors.New("no items match the specified selectors") + ErrorUnrecognizedService = errors.New("unrecognized service") ) const ( @@ -67,7 +70,7 @@ var ( const All = "All" type Reducer interface { - Reduce(context.Context, *details.Details) *details.Details + Reduce(context.Context, *details.Details, fault.Adder) *details.Details } // selectorResourceOwners aggregates all discrete path category types described @@ -234,13 +237,17 @@ func (s Selector) PathService() path.ServiceType { // from the generic selector by interpreting the selector service type rather // than have the caller make that interpretation. Returns an error if the // service is unsupported. -func (s Selector) Reduce(ctx context.Context, deets *details.Details) (*details.Details, error) { +func (s Selector) Reduce( + ctx context.Context, + deets *details.Details, + errs fault.Adder, +) (*details.Details, error) { r, err := selectorAsIface[Reducer](s) if err != nil { return nil, err } - return r.Reduce(ctx, deets), nil + return r.Reduce(ctx, deets, errs), nil } // returns the sets of path categories identified in each scope set. @@ -272,7 +279,7 @@ func selectorAsIface[T any](s Selector) (T, error) { a, err = func() (any, error) { return s.ToSharePointRestore() }() t = a.(T) default: - err = errors.New("service not supported: " + s.Service.String()) + err = clues.Stack(ErrorUnrecognizedService, errors.New(s.Service.String())) } return t, err @@ -374,7 +381,7 @@ func pathComparator() option { } func badCastErr(cast, is service) error { - return errors.Wrapf(ErrorBadSelectorCast, "%s service is not %s", cast, is) + return clues.Stack(ErrorBadSelectorCast, errors.Errorf("%s is not %s", cast, is)) } func join(s ...string) string { diff --git a/src/pkg/selectors/selectors_reduce_test.go b/src/pkg/selectors/selectors_reduce_test.go index 67b6bc9e2..3748f793a 100644 --- a/src/pkg/selectors/selectors_reduce_test.go +++ b/src/pkg/selectors/selectors_reduce_test.go @@ -10,6 +10,7 @@ import ( "github.com/alcionai/corso/src/internal/common" "github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault/mock" "github.com/alcionai/corso/src/pkg/selectors" "github.com/alcionai/corso/src/pkg/selectors/testdata" ) @@ -264,8 +265,11 @@ func (suite *SelectorReduceSuite) TestReduce() { for _, test := range table { suite.T().Run(test.name, func(t *testing.T) { - output := test.selFunc().Reduce(ctx, allDetails) + errs := mock.NewAdder() + + output := test.selFunc().Reduce(ctx, allDetails, errs) assert.ElementsMatch(t, test.expected, output.Entries) + assert.Empty(t, errs.Errs) }) } } diff --git a/src/pkg/selectors/sharepoint.go b/src/pkg/selectors/sharepoint.go index 7138acd6c..1df132e93 100644 --- a/src/pkg/selectors/sharepoint.go +++ b/src/pkg/selectors/sharepoint.go @@ -4,6 +4,7 @@ import ( "context" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" ) @@ -555,7 +556,11 @@ func (s SharePointScope) DiscreteCopy(site string) SharePointScope { // Reduce filters the entries in a details struct to only those that match the // inclusions, filters, and exclusions in the selector. -func (s sharePoint) Reduce(ctx context.Context, deets *details.Details) *details.Details { +func (s sharePoint) Reduce( + ctx context.Context, + deets *details.Details, + errs fault.Adder, +) *details.Details { return reduce[SharePointScope]( ctx, deets, @@ -565,7 +570,7 @@ func (s sharePoint) Reduce(ctx context.Context, deets *details.Details) *details path.ListsCategory: SharePointListItem, path.PagesCategory: SharePointPage, }, - ) + errs) } // matchesInfo handles the standard behavior when comparing a scope and an sharePointInfo diff --git a/src/pkg/selectors/sharepoint_test.go b/src/pkg/selectors/sharepoint_test.go index 4ce3859cd..2bf3f585c 100644 --- a/src/pkg/selectors/sharepoint_test.go +++ b/src/pkg/selectors/sharepoint_test.go @@ -9,6 +9,7 @@ import ( "github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/fault/mock" "github.com/alcionai/corso/src/pkg/path" ) @@ -305,10 +306,13 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { ctx, flush := tester.NewContext() defer flush() + errs := mock.NewAdder() + sel := test.makeSelector() - results := sel.Reduce(ctx, test.deets) + results := sel.Reduce(ctx, test.deets, errs) paths := results.Paths() assert.Equal(t, test.expect, paths) + assert.Empty(t, errs.Errs) }) } }