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] 🕐 Yes, but in a later PR #### Type of change - [x] 🌻 Feature #### Issue(s) * #3562 #### Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
a48b5f415c
commit
24c590040b
30
src/cli/flags/restore_config.go
Normal file
30
src/cli/flags/restore_config.go
Normal file
@ -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))
|
||||
}
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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"))
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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"))
|
||||
|
||||
@ -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)
|
||||
|
||||
4
src/cli/testdata/cli.go
vendored
4
src/cli/testdata/cli.go
vendored
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
65
src/cli/utils/restore_config.go
Normal file
65
src/cli/utils/restore_config.go
Normal file
@ -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
|
||||
}
|
||||
137
src/cli/utils/restore_config_test.go
Normal file
137
src/cli/utils/restore_config_test.go
Normal file
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
2
src/cli/utils/testdata/flags.go
vendored
2
src/cli/utils/testdata/flags.go
vendored
@ -44,6 +44,8 @@ var (
|
||||
PageFolderInput = []string{"pageFolder1", "pageFolder2"}
|
||||
PageInput = []string{"page1", "page2"}
|
||||
|
||||
Collisions = "collisions"
|
||||
Destination = "destination"
|
||||
RestorePermissions = true
|
||||
|
||||
AzureClientID = "testAzureClientId"
|
||||
|
||||
@ -72,6 +72,14 @@ const (
|
||||
Replace CollisionPolicy = "replace"
|
||||
)
|
||||
|
||||
func ValidCollisionPolicies() map[CollisionPolicy]struct{} {
|
||||
return map[CollisionPolicy]struct{}{
|
||||
Skip: {},
|
||||
Copy: {},
|
||||
Replace: {},
|
||||
}
|
||||
}
|
||||
|
||||
const RootLocation = "/"
|
||||
|
||||
// RestoreConfig contains
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user