From 24c590040b59eaa9ca744ad2fa14573e32695e4b Mon Sep 17 00:00:00 2001 From: Keepers Date: Thu, 6 Jul 2023 11:15:04 -0600 Subject: [PATCH] adds cli flags for restore config (#3704) implements cli integration for configuring restore operation collision policy and restore destination. flags are hidden and will be made visible at a later time. --- #### Does this PR need a docs update or release note? - [x] :clock1: Yes, but in a later PR #### Type of change - [x] :sunflower: Feature #### Issue(s) * #3562 #### Test Plan - [x] :zap: Unit test - [x] :green_heart: E2E --- src/cli/flags/restore_config.go | 30 +++++ src/cli/restore/exchange.go | 5 +- src/cli/restore/exchange_test.go | 10 ++ src/cli/restore/onedrive.go | 7 +- src/cli/restore/onedrive_test.go | 7 ++ src/cli/restore/sharepoint.go | 8 +- src/cli/restore/sharepoint_test.go | 7 ++ src/cli/testdata/cli.go | 4 +- src/cli/utils/exchange.go | 9 +- src/cli/utils/onedrive.go | 9 +- src/cli/utils/restore_config.go | 65 ++++++++++ src/cli/utils/restore_config_test.go | 137 +++++++++++++++++++++ src/cli/utils/sharepoint.go | 9 +- src/cli/utils/testdata/flags.go | 2 + src/pkg/control/options.go | 8 ++ src/pkg/control/{ => test}/options_test.go | 33 ++--- 16 files changed, 316 insertions(+), 34 deletions(-) create mode 100644 src/cli/flags/restore_config.go create mode 100644 src/cli/utils/restore_config.go create mode 100644 src/cli/utils/restore_config_test.go rename src/pkg/control/{ => test}/options_test.go (66%) diff --git a/src/cli/flags/restore_config.go b/src/cli/flags/restore_config.go new file mode 100644 index 000000000..8e5774f67 --- /dev/null +++ b/src/cli/flags/restore_config.go @@ -0,0 +1,30 @@ +package flags + +import ( + "github.com/spf13/cobra" + + "github.com/alcionai/corso/src/pkg/control" +) + +const ( + CollisionsFN = "collisions" + DestinationFN = "destination" +) + +var ( + CollisionsFV string + DestinationFV string +) + +// AddRestoreConfigFlags adds the restore config flag set. +func AddRestoreConfigFlags(cmd *cobra.Command) { + fs := cmd.Flags() + fs.StringVar( + &CollisionsFV, CollisionsFN, string(control.Skip), + "How to handle item collisions: "+string(control.Skip)+", "+string(control.Copy)+", or "+string(control.Replace)) + cobra.CheckErr(fs.MarkHidden(CollisionsFN)) + fs.StringVar( + &DestinationFV, DestinationFN, "", + "Overrides the destination where items get restored. '/' places items back in their original location.") + cobra.CheckErr(fs.MarkHidden(DestinationFN)) +} diff --git a/src/cli/restore/exchange.go b/src/cli/restore/exchange.go index 847e09d83..2cb449563 100644 --- a/src/cli/restore/exchange.go +++ b/src/cli/restore/exchange.go @@ -12,7 +12,6 @@ import ( "github.com/alcionai/corso/src/cli/utils" "github.com/alcionai/corso/src/internal/common/dttm" "github.com/alcionai/corso/src/internal/data" - "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/path" ) @@ -36,6 +35,7 @@ func addExchangeCommands(cmd *cobra.Command) *cobra.Command { flags.AddBackupIDFlag(c, true) flags.AddExchangeDetailsAndRestoreFlags(c) + flags.AddRestoreConfigFlags(c) flags.AddFailFastFlag(c) flags.AddCorsoPassphaseFlags(c) flags.AddAWSCredsFlags(c) @@ -101,8 +101,7 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error { defer utils.CloseRepo(ctx, r) - restoreCfg := control.DefaultRestoreConfig(dttm.HumanReadable) - Infof(ctx, "Restoring to folder %s", restoreCfg.Location) + restoreCfg := utils.MakeRestoreConfig(ctx, opts.RestoreCfg, dttm.HumanReadable) sel := utils.IncludeExchangeRestoreDataSelectors(opts) utils.FilterExchangeRestoreInfoSelectors(sel, opts) diff --git a/src/cli/restore/exchange_test.go b/src/cli/restore/exchange_test.go index 8bf7bebea..0dd022a81 100644 --- a/src/cli/restore/exchange_test.go +++ b/src/cli/restore/exchange_test.go @@ -62,15 +62,18 @@ func (suite *ExchangeUnitSuite) TestAddExchangeCommands() { "exchange", "--" + flags.RunModeFN, flags.RunModeFlagTest, "--" + flags.BackupFN, testdata.BackupInput, + "--" + flags.ContactFN, testdata.FlgInputs(testdata.ContactInput), "--" + flags.ContactFolderFN, testdata.FlgInputs(testdata.ContactFldInput), "--" + flags.ContactNameFN, testdata.ContactNameInput, + "--" + flags.EmailFN, testdata.FlgInputs(testdata.EmailInput), "--" + flags.EmailFolderFN, testdata.FlgInputs(testdata.EmailFldInput), "--" + flags.EmailReceivedAfterFN, testdata.EmailReceivedAfterInput, "--" + flags.EmailReceivedBeforeFN, testdata.EmailReceivedBeforeInput, "--" + flags.EmailSenderFN, testdata.EmailSenderInput, "--" + flags.EmailSubjectFN, testdata.EmailSubjectInput, + "--" + flags.EventFN, testdata.FlgInputs(testdata.EventInput), "--" + flags.EventCalendarFN, testdata.FlgInputs(testdata.EventCalInput), "--" + flags.EventOrganizerFN, testdata.EventOrganizerInput, @@ -78,6 +81,10 @@ func (suite *ExchangeUnitSuite) TestAddExchangeCommands() { "--" + flags.EventStartsAfterFN, testdata.EventStartsAfterInput, "--" + flags.EventStartsBeforeFN, testdata.EventStartsBeforeInput, "--" + flags.EventSubjectFN, testdata.EventSubjectInput, + + "--" + flags.CollisionsFN, testdata.Collisions, + "--" + flags.DestinationFN, testdata.Destination, + "--" + flags.AWSAccessKeyFN, testdata.AWSAccessKeyID, "--" + flags.AWSSecretAccessKeyFN, testdata.AWSSecretAccessKey, "--" + flags.AWSSessionTokenFN, testdata.AWSSessionToken, @@ -116,6 +123,9 @@ func (suite *ExchangeUnitSuite) TestAddExchangeCommands() { assert.Equal(t, testdata.EventStartsBeforeInput, opts.EventStartsBefore) assert.Equal(t, testdata.EventSubjectInput, opts.EventSubject) + assert.Equal(t, testdata.Collisions, opts.RestoreCfg.Collisions) + assert.Equal(t, testdata.Destination, opts.RestoreCfg.Destination) + assert.Equal(t, testdata.AWSAccessKeyID, flags.AWSAccessKeyFV) assert.Equal(t, testdata.AWSSecretAccessKey, flags.AWSSecretAccessKeyFV) assert.Equal(t, testdata.AWSSessionToken, flags.AWSSessionTokenFV) diff --git a/src/cli/restore/onedrive.go b/src/cli/restore/onedrive.go index d19f9d891..464c9a7b4 100644 --- a/src/cli/restore/onedrive.go +++ b/src/cli/restore/onedrive.go @@ -12,7 +12,6 @@ import ( "github.com/alcionai/corso/src/cli/utils" "github.com/alcionai/corso/src/internal/common/dttm" "github.com/alcionai/corso/src/internal/data" - "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/path" ) @@ -36,6 +35,7 @@ func addOneDriveCommands(cmd *cobra.Command) *cobra.Command { flags.AddBackupIDFlag(c, true) flags.AddOneDriveDetailsAndRestoreFlags(c) flags.AddRestorePermissionsFlag(c) + flags.AddRestoreConfigFlags(c) flags.AddFailFastFlag(c) flags.AddCorsoPassphaseFlags(c) flags.AddAWSCredsFlags(c) @@ -100,12 +100,11 @@ func restoreOneDriveCmd(cmd *cobra.Command, args []string) error { defer utils.CloseRepo(ctx, r) - restoreCfg := control.DefaultRestoreConfig(dttm.HumanReadableDriveItem) - Infof(ctx, "Restoring to folder %s", restoreCfg.Location) - sel := utils.IncludeOneDriveRestoreDataSelectors(opts) utils.FilterOneDriveRestoreInfoSelectors(sel, opts) + restoreCfg := utils.MakeRestoreConfig(ctx, opts.RestoreCfg, dttm.HumanReadableDriveItem) + ro, err := r.NewRestore(ctx, flags.BackupIDFV, sel.Selector, restoreCfg) if err != nil { return Only(ctx, clues.Wrap(err, "Failed to initialize OneDrive restore")) diff --git a/src/cli/restore/onedrive_test.go b/src/cli/restore/onedrive_test.go index 41aa5d29c..a21f1191d 100644 --- a/src/cli/restore/onedrive_test.go +++ b/src/cli/restore/onedrive_test.go @@ -67,6 +67,10 @@ func (suite *OneDriveUnitSuite) TestAddOneDriveCommands() { "--" + flags.FileCreatedBeforeFN, testdata.FileCreatedBeforeInput, "--" + flags.FileModifiedAfterFN, testdata.FileModifiedAfterInput, "--" + flags.FileModifiedBeforeFN, testdata.FileModifiedBeforeInput, + + "--" + flags.CollisionsFN, testdata.Collisions, + "--" + flags.DestinationFN, testdata.Destination, + "--" + flags.AWSAccessKeyFN, testdata.AWSAccessKeyID, "--" + flags.AWSSecretAccessKeyFN, testdata.AWSSecretAccessKey, "--" + flags.AWSSessionTokenFN, testdata.AWSSessionToken, @@ -93,6 +97,9 @@ func (suite *OneDriveUnitSuite) TestAddOneDriveCommands() { assert.Equal(t, testdata.FileModifiedAfterInput, opts.FileModifiedAfter) assert.Equal(t, testdata.FileModifiedBeforeInput, opts.FileModifiedBefore) + assert.Equal(t, testdata.Collisions, opts.RestoreCfg.Collisions) + assert.Equal(t, testdata.Destination, opts.RestoreCfg.Destination) + assert.Equal(t, testdata.AWSAccessKeyID, flags.AWSAccessKeyFV) assert.Equal(t, testdata.AWSSecretAccessKey, flags.AWSSecretAccessKeyFV) assert.Equal(t, testdata.AWSSessionToken, flags.AWSSessionTokenFV) diff --git a/src/cli/restore/sharepoint.go b/src/cli/restore/sharepoint.go index d9fb0b95d..f5cbc71fd 100644 --- a/src/cli/restore/sharepoint.go +++ b/src/cli/restore/sharepoint.go @@ -12,7 +12,6 @@ import ( "github.com/alcionai/corso/src/cli/utils" "github.com/alcionai/corso/src/internal/common/dttm" "github.com/alcionai/corso/src/internal/data" - "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/path" ) @@ -36,8 +35,8 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command { flags.AddBackupIDFlag(c, true) flags.AddSharePointDetailsAndRestoreFlags(c) flags.AddRestorePermissionsFlag(c) + flags.AddRestoreConfigFlags(c) flags.AddFailFastFlag(c) - flags.AddCorsoPassphaseFlags(c) flags.AddAWSCredsFlags(c) flags.AddAzureCredsFlags(c) @@ -107,12 +106,11 @@ func restoreSharePointCmd(cmd *cobra.Command, args []string) error { defer utils.CloseRepo(ctx, r) - restoreCfg := control.DefaultRestoreConfig(dttm.HumanReadableDriveItem) - Infof(ctx, "Restoring to folder %s", restoreCfg.Location) - sel := utils.IncludeSharePointRestoreDataSelectors(ctx, opts) utils.FilterSharePointRestoreInfoSelectors(sel, opts) + restoreCfg := utils.MakeRestoreConfig(ctx, opts.RestoreCfg, dttm.HumanReadableDriveItem) + ro, err := r.NewRestore(ctx, flags.BackupIDFV, sel.Selector, restoreCfg) if err != nil { return Only(ctx, clues.Wrap(err, "Failed to initialize SharePoint restore")) diff --git a/src/cli/restore/sharepoint_test.go b/src/cli/restore/sharepoint_test.go index 5e0505dd5..b4547077f 100644 --- a/src/cli/restore/sharepoint_test.go +++ b/src/cli/restore/sharepoint_test.go @@ -72,6 +72,10 @@ func (suite *SharePointUnitSuite) TestAddSharePointCommands() { "--" + flags.ListFolderFN, testdata.FlgInputs(testdata.ListFolderInput), "--" + flags.PageFN, testdata.FlgInputs(testdata.PageInput), "--" + flags.PageFolderFN, testdata.FlgInputs(testdata.PageFolderInput), + + "--" + flags.CollisionsFN, testdata.Collisions, + "--" + flags.DestinationFN, testdata.Destination, + "--" + flags.AWSAccessKeyFN, testdata.AWSAccessKeyID, "--" + flags.AWSSecretAccessKeyFN, testdata.AWSSecretAccessKey, "--" + flags.AWSSessionTokenFN, testdata.AWSSessionToken, @@ -105,6 +109,9 @@ func (suite *SharePointUnitSuite) TestAddSharePointCommands() { assert.ElementsMatch(t, testdata.PageInput, opts.Page) assert.ElementsMatch(t, testdata.PageFolderInput, opts.PageFolder) + assert.Equal(t, testdata.Collisions, opts.RestoreCfg.Collisions) + assert.Equal(t, testdata.Destination, opts.RestoreCfg.Destination) + assert.Equal(t, testdata.AWSAccessKeyID, flags.AWSAccessKeyFV) assert.Equal(t, testdata.AWSSecretAccessKey, flags.AWSSecretAccessKeyFV) assert.Equal(t, testdata.AWSSessionToken, flags.AWSSessionTokenFV) diff --git a/src/cli/testdata/cli.go b/src/cli/testdata/cli.go index 27a023e72..1c955165f 100644 --- a/src/cli/testdata/cli.go +++ b/src/cli/testdata/cli.go @@ -6,15 +6,13 @@ import ( "github.com/google/uuid" "github.com/spf13/cobra" - - "github.com/alcionai/corso/src/internal/common/dttm" ) // StubRootCmd builds a stub cobra command to be used as // the root command for integration testing on the CLI func StubRootCmd(args ...string) *cobra.Command { id := uuid.NewString() - now := dttm.Format(time.Now()) + now := time.Now().UTC().Format(time.RFC3339Nano) cmdArg := "testing-corso" c := &cobra.Command{ Use: cmdArg, diff --git a/src/cli/utils/exchange.go b/src/cli/utils/exchange.go index 7051d5904..1c2ba9005 100644 --- a/src/cli/utils/exchange.go +++ b/src/cli/utils/exchange.go @@ -30,6 +30,8 @@ type ExchangeOpts struct { EventStartsBefore string EventSubject string + RestoreCfg RestoreCfgOpts + Populated flags.PopulatedFlags } @@ -57,6 +59,11 @@ func MakeExchangeOpts(cmd *cobra.Command) ExchangeOpts { EventStartsBefore: flags.EventStartsBeforeFV, EventSubject: flags.EventSubjectFV, + RestoreCfg: makeRestoreCfgOpts(cmd), + + // populated contains the list of flags that appear in the + // command, according to pflags. Use this to differentiate + // between an "empty" and a "missing" value. Populated: flags.GetPopulatedFlags(cmd), } } @@ -132,7 +139,7 @@ func ValidateExchangeRestoreFlags(backupID string, opts ExchangeOpts) error { return clues.New("invalid format for event-recurs") } - return nil + return validateRestoreConfigFlags(flags.CollisionsFV, opts.RestoreCfg) } // IncludeExchangeRestoreDataSelectors builds the common data-selector diff --git a/src/cli/utils/onedrive.go b/src/cli/utils/onedrive.go index 16c9c8d8f..06699adca 100644 --- a/src/cli/utils/onedrive.go +++ b/src/cli/utils/onedrive.go @@ -18,6 +18,8 @@ type OneDriveOpts struct { FileModifiedAfter string FileModifiedBefore string + RestoreCfg RestoreCfgOpts + Populated flags.PopulatedFlags } @@ -32,6 +34,11 @@ func MakeOneDriveOpts(cmd *cobra.Command) OneDriveOpts { FileModifiedAfter: flags.FileModifiedAfterFV, FileModifiedBefore: flags.FileModifiedBeforeFV, + RestoreCfg: makeRestoreCfgOpts(cmd), + + // populated contains the list of flags that appear in the + // command, according to pflags. Use this to differentiate + // between an "empty" and a "missing" value. Populated: flags.GetPopulatedFlags(cmd), } } @@ -58,7 +65,7 @@ func ValidateOneDriveRestoreFlags(backupID string, opts OneDriveOpts) error { return clues.New("invalid time format for modified-before") } - return nil + return validateRestoreConfigFlags(flags.CollisionsFV, opts.RestoreCfg) } // AddOneDriveFilter adds the scope of the provided values to the selector's diff --git a/src/cli/utils/restore_config.go b/src/cli/utils/restore_config.go new file mode 100644 index 000000000..172d49d5d --- /dev/null +++ b/src/cli/utils/restore_config.go @@ -0,0 +1,65 @@ +package utils + +import ( + "context" + + "github.com/alcionai/clues" + "github.com/spf13/cobra" + + "github.com/alcionai/corso/src/cli/flags" + . "github.com/alcionai/corso/src/cli/print" + "github.com/alcionai/corso/src/internal/common/dttm" + "github.com/alcionai/corso/src/pkg/control" +) + +type RestoreCfgOpts struct { + Collisions string + Destination string + + Populated flags.PopulatedFlags +} + +func makeRestoreCfgOpts(cmd *cobra.Command) RestoreCfgOpts { + return RestoreCfgOpts{ + Collisions: flags.CollisionsFV, + Destination: flags.DestinationFV, + + // populated contains the list of flags that appear in the + // command, according to pflags. Use this to differentiate + // between an "empty" and a "missing" value. + Populated: flags.GetPopulatedFlags(cmd), + } +} + +// validateRestoreConfigFlags checks common restore flags for +// correctness and interdependencies. +func validateRestoreConfigFlags(fv string, opts RestoreCfgOpts) error { + _, populated := opts.Populated[flags.CollisionsFN] + _, foundInValidSet := control.ValidCollisionPolicies()[control.CollisionPolicy(fv)] + + if populated && !foundInValidSet { + return clues.New("invalid entry for " + flags.CollisionsFN) + } + + return nil +} + +func MakeRestoreConfig( + ctx context.Context, + opts RestoreCfgOpts, + locationTimeFormat dttm.TimeFormat, +) control.RestoreConfig { + restoreCfg := control.DefaultRestoreConfig(locationTimeFormat) + + if _, ok := opts.Populated[flags.CollisionsFN]; ok { + restoreCfg.OnCollision = control.CollisionPolicy(opts.Collisions) + } + + if _, ok := opts.Populated[flags.DestinationFN]; ok { + restoreCfg.Location = opts.Destination + } + + Infof(ctx, "Restoring to folder %s", restoreCfg.Location) + + return restoreCfg +} diff --git a/src/cli/utils/restore_config_test.go b/src/cli/utils/restore_config_test.go new file mode 100644 index 000000000..513797d39 --- /dev/null +++ b/src/cli/utils/restore_config_test.go @@ -0,0 +1,137 @@ +package utils + +import ( + "testing" + + "github.com/alcionai/clues" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + "github.com/alcionai/corso/src/cli/flags" + "github.com/alcionai/corso/src/internal/common/dttm" + "github.com/alcionai/corso/src/internal/tester" + "github.com/alcionai/corso/src/pkg/control" +) + +type RestoreCfgUnitSuite struct { + tester.Suite +} + +func TestRestoreCfgUnitSuite(t *testing.T) { + suite.Run(t, &RestoreCfgUnitSuite{Suite: tester.NewUnitSuite(t)}) +} + +func (suite *RestoreCfgUnitSuite) TestValidateRestoreConfigFlags() { + table := []struct { + name string + fv string + opts RestoreCfgOpts + expect assert.ErrorAssertionFunc + }{ + { + name: "no error", + fv: string(control.Skip), + opts: RestoreCfgOpts{ + Collisions: string(control.Skip), + Populated: flags.PopulatedFlags{ + flags.CollisionsFN: {}, + }, + }, + expect: assert.NoError, + }, + { + name: "bad but not populated", + fv: "foo", + opts: RestoreCfgOpts{ + Collisions: "foo", + Populated: flags.PopulatedFlags{}, + }, + expect: assert.NoError, + }, + { + name: "error", + fv: "foo", + opts: RestoreCfgOpts{ + Collisions: "foo", + Populated: flags.PopulatedFlags{ + flags.CollisionsFN: {}, + }, + }, + expect: assert.Error, + }, + } + for _, test := range table { + suite.Run(test.name, func() { + err := validateRestoreConfigFlags(test.fv, test.opts) + test.expect(suite.T(), err, clues.ToCore(err)) + }) + } +} + +func (suite *RestoreCfgUnitSuite) TestMakeRestoreConfig() { + rco := &RestoreCfgOpts{ + Collisions: "collisions", + Destination: "destination", + } + + table := []struct { + name string + populated flags.PopulatedFlags + expect control.RestoreConfig + }{ + { + name: "not populated", + populated: flags.PopulatedFlags{}, + expect: control.RestoreConfig{ + OnCollision: control.Skip, + Location: "Corso_Restore_", + }, + }, + { + name: "collision populated", + populated: flags.PopulatedFlags{ + flags.CollisionsFN: {}, + }, + expect: control.RestoreConfig{ + OnCollision: control.CollisionPolicy("collisions"), + Location: "Corso_Restore_", + }, + }, + { + name: "destination populated", + populated: flags.PopulatedFlags{ + flags.DestinationFN: {}, + }, + expect: control.RestoreConfig{ + OnCollision: control.Skip, + Location: "destination", + }, + }, + { + name: "both populated", + populated: flags.PopulatedFlags{ + flags.CollisionsFN: {}, + flags.DestinationFN: {}, + }, + expect: control.RestoreConfig{ + OnCollision: control.CollisionPolicy("collisions"), + Location: "destination", + }, + }, + } + for _, test := range table { + suite.Run(test.name, func() { + t := suite.T() + + ctx, flush := tester.NewContext(t) + defer flush() + + opts := *rco + opts.Populated = test.populated + + result := MakeRestoreConfig(ctx, opts, dttm.HumanReadable) + assert.Equal(t, test.expect.OnCollision, result.OnCollision) + assert.Contains(t, result.Location, test.expect.Location) + }) + } +} diff --git a/src/cli/utils/sharepoint.go b/src/cli/utils/sharepoint.go index 78b6e947f..6672beda1 100644 --- a/src/cli/utils/sharepoint.go +++ b/src/cli/utils/sharepoint.go @@ -31,6 +31,8 @@ type SharePointOpts struct { PageFolder []string Page []string + RestoreCfg RestoreCfgOpts + Populated flags.PopulatedFlags } @@ -53,6 +55,11 @@ func MakeSharePointOpts(cmd *cobra.Command) SharePointOpts { Page: flags.PageFV, PageFolder: flags.PageFolderFV, + RestoreCfg: makeRestoreCfgOpts(cmd), + + // populated contains the list of flags that appear in the + // command, according to pflags. Use this to differentiate + // between an "empty" and a "missing" value. Populated: flags.GetPopulatedFlags(cmd), } } @@ -88,7 +95,7 @@ func ValidateSharePointRestoreFlags(backupID string, opts SharePointOpts) error return clues.New("invalid time format for " + flags.FileModifiedBeforeFN) } - return nil + return validateRestoreConfigFlags(flags.CollisionsFV, opts.RestoreCfg) } // AddSharePointInfo adds the scope of the provided values to the selector's diff --git a/src/cli/utils/testdata/flags.go b/src/cli/utils/testdata/flags.go index 67992e267..f97529b57 100644 --- a/src/cli/utils/testdata/flags.go +++ b/src/cli/utils/testdata/flags.go @@ -44,6 +44,8 @@ var ( PageFolderInput = []string{"pageFolder1", "pageFolder2"} PageInput = []string{"page1", "page2"} + Collisions = "collisions" + Destination = "destination" RestorePermissions = true AzureClientID = "testAzureClientId" diff --git a/src/pkg/control/options.go b/src/pkg/control/options.go index 91fe33cbb..2c560870d 100644 --- a/src/pkg/control/options.go +++ b/src/pkg/control/options.go @@ -72,6 +72,14 @@ const ( Replace CollisionPolicy = "replace" ) +func ValidCollisionPolicies() map[CollisionPolicy]struct{} { + return map[CollisionPolicy]struct{}{ + Skip: {}, + Copy: {}, + Replace: {}, + } +} + const RootLocation = "/" // RestoreConfig contains diff --git a/src/pkg/control/options_test.go b/src/pkg/control/test/options_test.go similarity index 66% rename from src/pkg/control/options_test.go rename to src/pkg/control/test/options_test.go index eac04ddfa..fba4e3cac 100644 --- a/src/pkg/control/options_test.go +++ b/src/pkg/control/test/options_test.go @@ -1,4 +1,4 @@ -package control +package test import ( "testing" @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/alcionai/corso/src/internal/tester" + "github.com/alcionai/corso/src/pkg/control" ) type OptionsUnitSuite struct { @@ -20,19 +21,19 @@ func TestOptionsUnitSuite(t *testing.T) { func (suite *OptionsUnitSuite) TestEnsureRestoreConfigDefaults() { table := []struct { name string - input RestoreConfig - expect RestoreConfig + input control.RestoreConfig + expect control.RestoreConfig }{ { name: "populated", - input: RestoreConfig{ - OnCollision: Copy, + input: control.RestoreConfig{ + OnCollision: control.Copy, ProtectedResource: "batman", Location: "badman", Drive: "hatman", }, - expect: RestoreConfig{ - OnCollision: Copy, + expect: control.RestoreConfig{ + OnCollision: control.Copy, ProtectedResource: "batman", Location: "badman", Drive: "hatman", @@ -40,14 +41,14 @@ func (suite *OptionsUnitSuite) TestEnsureRestoreConfigDefaults() { }, { name: "unpopulated", - input: RestoreConfig{ - OnCollision: Unknown, + input: control.RestoreConfig{ + OnCollision: control.Unknown, ProtectedResource: "", Location: "", Drive: "", }, - expect: RestoreConfig{ - OnCollision: Skip, + expect: control.RestoreConfig{ + OnCollision: control.Skip, ProtectedResource: "", Location: "", Drive: "", @@ -55,14 +56,14 @@ func (suite *OptionsUnitSuite) TestEnsureRestoreConfigDefaults() { }, { name: "populated, but modified", - input: RestoreConfig{ - OnCollision: CollisionPolicy("batman"), + input: control.RestoreConfig{ + OnCollision: control.CollisionPolicy("batman"), ProtectedResource: "", Location: "/", Drive: "", }, - expect: RestoreConfig{ - OnCollision: Skip, + expect: control.RestoreConfig{ + OnCollision: control.Skip, ProtectedResource: "", Location: "", Drive: "", @@ -76,7 +77,7 @@ func (suite *OptionsUnitSuite) TestEnsureRestoreConfigDefaults() { ctx, flush := tester.NewContext(t) defer flush() - result := EnsureRestoreConfigDefaults(ctx, test.input) + result := control.EnsureRestoreConfigDefaults(ctx, test.input) assert.Equal(t, test.expect, result) }) }