OneDrive CLI commands (#739)
## Description Wires up the OneDrive Backup(create,list,details,delete) and Restore commands Unit tests added but integration tests will be added after the underlying operation PRs are merged. ## Type of change Please check the type of change your PR introduces: - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 🐹 Trivial/Minor ## Issue(s) #658 #668 ## Test Plan <!-- How will this be tested prior to merging.--> - [x] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
31e4a68355
commit
a9b0e2e7ee
@ -13,6 +13,7 @@ var subCommands = []*cobra.Command{
|
||||
|
||||
var serviceCommands = []func(parent *cobra.Command) *cobra.Command{
|
||||
addExchangeCommands,
|
||||
addOneDriveCommands,
|
||||
}
|
||||
|
||||
// AddCommands attaches all `corso backup * *` commands to the parent.
|
||||
|
||||
252
src/cli/backup/onedrive.go
Normal file
252
src/cli/backup/onedrive.go
Normal file
@ -0,0 +1,252 @@
|
||||
package backup
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/alcionai/corso/src/cli/config"
|
||||
"github.com/alcionai/corso/src/cli/options"
|
||||
. "github.com/alcionai/corso/src/cli/print"
|
||||
"github.com/alcionai/corso/src/cli/utils"
|
||||
"github.com/alcionai/corso/src/internal/model"
|
||||
"github.com/alcionai/corso/src/pkg/backup"
|
||||
"github.com/alcionai/corso/src/pkg/repository"
|
||||
"github.com/alcionai/corso/src/pkg/selectors"
|
||||
)
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// setup and globals
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
const oneDriveServiceCommand = "onedrive"
|
||||
|
||||
// called by backup.go to map parent subcommands to provider-specific handling.
|
||||
func addOneDriveCommands(parent *cobra.Command) *cobra.Command {
|
||||
var (
|
||||
c *cobra.Command
|
||||
fs *pflag.FlagSet
|
||||
)
|
||||
|
||||
switch parent.Use {
|
||||
case createCommand:
|
||||
c, fs = utils.AddCommand(parent, oneDriveCreateCmd())
|
||||
|
||||
fs.StringArrayVar(&user, "user", nil,
|
||||
"Backup OneDrive data by user ID; accepts "+utils.Wildcard+" to select all users")
|
||||
options.AddOperationFlags(c)
|
||||
|
||||
case listCommand:
|
||||
c, _ = utils.AddCommand(parent, oneDriveListCmd())
|
||||
|
||||
case detailsCommand:
|
||||
c, fs = utils.AddCommand(parent, oneDriveDetailsCmd())
|
||||
fs.StringVar(&backupID, "backup", "", "ID of the backup containing the details to be shown")
|
||||
cobra.CheckErr(c.MarkFlagRequired("backup"))
|
||||
|
||||
case deleteCommand:
|
||||
c, fs = utils.AddCommand(parent, oneDriveDeleteCmd())
|
||||
fs.StringVar(&backupID, "backup", "", "ID of the backup containing the details to be shown")
|
||||
cobra.CheckErr(c.MarkFlagRequired("backup"))
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// backup create
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// `corso backup create onedrive [<flag>...]`
|
||||
func oneDriveCreateCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: oneDriveServiceCommand,
|
||||
Short: "Backup M365 OneDrive service data",
|
||||
RunE: createOneDriveCmd,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
}
|
||||
|
||||
// processes an onedrive service backup.
|
||||
func createOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := validateOneDriveBackupCreateFlags(user); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, acct, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||
if err != nil {
|
||||
return Only(ctx, err)
|
||||
}
|
||||
|
||||
r, err := repository.Connect(ctx, acct, s, options.Control())
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||
}
|
||||
|
||||
defer utils.CloseRepo(ctx, r)
|
||||
|
||||
sel := oneDriveBackupCreateSelectors(user)
|
||||
|
||||
bo, err := r.NewBackup(ctx, sel)
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrap(err, "Failed to initialize OneDrive backup"))
|
||||
}
|
||||
|
||||
err = bo.Run(ctx)
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrap(err, "Failed to run OneDrive backup"))
|
||||
}
|
||||
|
||||
bu, err := r.Backup(ctx, bo.Results.BackupID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to retrieve backup results from storage")
|
||||
}
|
||||
|
||||
bu.Print(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateOneDriveBackupCreateFlags(users []string) error {
|
||||
if len(users) == 0 {
|
||||
return errors.New("requires one or more --user ids or the wildcard --user *")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func oneDriveBackupCreateSelectors(users []string) selectors.Selector {
|
||||
sel := selectors.NewOneDriveBackup()
|
||||
sel.Include(sel.Users(users))
|
||||
|
||||
return sel.Selector
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// backup list
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// `corso backup list onedrive [<flag>...]`
|
||||
func oneDriveListCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: oneDriveServiceCommand,
|
||||
Short: "List the history of M365 OneDrive service backups",
|
||||
RunE: listOneDriveCmd,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
}
|
||||
|
||||
// lists the history of backup operations
|
||||
func listOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
s, acct, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||
if err != nil {
|
||||
return Only(ctx, err)
|
||||
}
|
||||
|
||||
r, err := repository.Connect(ctx, acct, s, options.Control())
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||
}
|
||||
|
||||
defer utils.CloseRepo(ctx, r)
|
||||
|
||||
bs, err := r.Backups(ctx)
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrap(err, "Failed to list backups in the repository"))
|
||||
}
|
||||
|
||||
backup.PrintAll(ctx, bs)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// backup details
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// `corso backup details onedrive [<flag>...]`
|
||||
func oneDriveDetailsCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: oneDriveServiceCommand,
|
||||
Short: "Shows the details of a M365 OneDrive service backup",
|
||||
RunE: detailsOneDriveCmd,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
}
|
||||
|
||||
// lists the history of backup operations
|
||||
func detailsOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, acct, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||
if err != nil {
|
||||
return Only(ctx, err)
|
||||
}
|
||||
|
||||
r, err := repository.Connect(ctx, acct, s, options.Control())
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||
}
|
||||
|
||||
defer utils.CloseRepo(ctx, r)
|
||||
|
||||
ds, _, err := r.BackupDetails(ctx, backupID)
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrap(err, "Failed to get backup details in the repository"))
|
||||
}
|
||||
|
||||
// TODO: Support selectors and filters
|
||||
|
||||
ds.PrintEntries(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// `corso backup delete onedrive [<flag>...]`
|
||||
func oneDriveDeleteCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: oneDriveServiceCommand,
|
||||
Short: "Delete backed-up M365 OneDrive service data",
|
||||
RunE: deleteOneDriveCmd,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
}
|
||||
|
||||
// deletes an exchange service backup.
|
||||
func deleteOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, acct, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||
if err != nil {
|
||||
return Only(ctx, err)
|
||||
}
|
||||
|
||||
r, err := repository.Connect(ctx, acct, s, options.Control())
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||
}
|
||||
|
||||
defer utils.CloseRepo(ctx, r)
|
||||
|
||||
if err := r.DeleteBackup(ctx, model.StableID(backupID)); err != nil {
|
||||
return Only(ctx, errors.Wrapf(err, "Deleting backup %s", backupID))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
76
src/cli/backup/onedrive_test.go
Normal file
76
src/cli/backup/onedrive_test.go
Normal file
@ -0,0 +1,76 @@
|
||||
package backup
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/tester"
|
||||
)
|
||||
|
||||
type OneDriveSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func TestOneDriveSuite(t *testing.T) {
|
||||
suite.Run(t, new(OneDriveSuite))
|
||||
}
|
||||
|
||||
func (suite *OneDriveSuite) TestAddOneDriveCommands() {
|
||||
expectUse := oneDriveServiceCommand
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
use string
|
||||
expectUse string
|
||||
expectShort string
|
||||
expectRunE func(*cobra.Command, []string) error
|
||||
}{
|
||||
{"create onedrive", createCommand, expectUse, oneDriveCreateCmd().Short, createOneDriveCmd},
|
||||
{"list onedrive", listCommand, expectUse, oneDriveListCmd().Short, listOneDriveCmd},
|
||||
{"details onedrive", detailsCommand, expectUse, oneDriveDetailsCmd().Short, detailsOneDriveCmd},
|
||||
{"delete onedrive", deleteCommand, expectUse, oneDriveDeleteCmd().Short, deleteOneDriveCmd},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
cmd := &cobra.Command{Use: test.use}
|
||||
|
||||
c := addOneDriveCommands(cmd)
|
||||
require.NotNil(t, c)
|
||||
|
||||
cmds := cmd.Commands()
|
||||
require.Len(t, cmds, 1)
|
||||
|
||||
child := cmds[0]
|
||||
assert.Equal(t, test.expectUse, child.Use)
|
||||
assert.Equal(t, test.expectShort, child.Short)
|
||||
tester.AreSameFunc(t, test.expectRunE, child.RunE)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *OneDriveSuite) TestValidateOneDriveBackupCreateFlags() {
|
||||
table := []struct {
|
||||
name string
|
||||
user []string
|
||||
expect assert.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "no users",
|
||||
expect: assert.Error,
|
||||
},
|
||||
{
|
||||
name: "users",
|
||||
user: []string{"fnord"},
|
||||
expect: assert.NoError,
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
test.expect(t, validateOneDriveBackupCreateFlags(test.user))
|
||||
})
|
||||
}
|
||||
}
|
||||
98
src/cli/restore/onedrive.go
Normal file
98
src/cli/restore/onedrive.go
Normal file
@ -0,0 +1,98 @@
|
||||
package restore
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/alcionai/corso/src/cli/config"
|
||||
"github.com/alcionai/corso/src/cli/options"
|
||||
. "github.com/alcionai/corso/src/cli/print"
|
||||
"github.com/alcionai/corso/src/cli/utils"
|
||||
"github.com/alcionai/corso/src/pkg/repository"
|
||||
"github.com/alcionai/corso/src/pkg/selectors"
|
||||
)
|
||||
|
||||
// called by restore.go to map parent subcommands to provider-specific handling.
|
||||
func addOneDriveCommands(parent *cobra.Command) *cobra.Command {
|
||||
var (
|
||||
c *cobra.Command
|
||||
fs *pflag.FlagSet
|
||||
)
|
||||
|
||||
switch parent.Use {
|
||||
case restoreCommand:
|
||||
c, fs = utils.AddCommand(parent, oneDriveRestoreCmd())
|
||||
fs.StringVar(&backupID, "backup", "", "ID of the backup to restore")
|
||||
cobra.CheckErr(c.MarkFlagRequired("backup"))
|
||||
|
||||
fs.StringSliceVar(&user,
|
||||
"user", nil,
|
||||
"Restore all data by user ID; accepts "+utils.Wildcard+" to select all users")
|
||||
|
||||
// others
|
||||
options.AddOperationFlags(c)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
const oneDriveServiceCommand = "onedrive"
|
||||
|
||||
// `corso restore onedrive [<flag>...]`
|
||||
func oneDriveRestoreCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: oneDriveServiceCommand,
|
||||
Short: "Restore M365 OneDrive service data",
|
||||
RunE: restoreOneDriveCmd,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
}
|
||||
|
||||
// processes an onedrive service restore.
|
||||
func restoreOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := utils.ValidateOneDriveRestoreFlags(backupID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, a, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||
if err != nil {
|
||||
return Only(ctx, err)
|
||||
}
|
||||
|
||||
r, err := repository.Connect(ctx, a, s, options.Control())
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||
}
|
||||
|
||||
defer utils.CloseRepo(ctx, r)
|
||||
|
||||
sel := selectors.NewOneDriveRestore()
|
||||
if user != nil {
|
||||
sel.Include(sel.Users(user))
|
||||
}
|
||||
|
||||
// if no selector flags were specified, get all data in the service.
|
||||
if len(sel.Scopes()) == 0 {
|
||||
sel.Include(sel.Users(selectors.Any()))
|
||||
}
|
||||
|
||||
ro, err := r.NewRestore(ctx, backupID, sel.Selector)
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrap(err, "Failed to initialize OneDrive restore"))
|
||||
}
|
||||
|
||||
if err := ro.Run(ctx); err != nil {
|
||||
return Only(ctx, errors.Wrap(err, "Failed to run OneDrive restore"))
|
||||
}
|
||||
|
||||
Infof(ctx, "Restored OneDrive in %s for user %s.\n", s.Provider, sel.ToPrintable().Resources())
|
||||
|
||||
return nil
|
||||
}
|
||||
50
src/cli/restore/onedrive_test.go
Normal file
50
src/cli/restore/onedrive_test.go
Normal file
@ -0,0 +1,50 @@
|
||||
package restore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/tester"
|
||||
)
|
||||
|
||||
type OneDriveSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func TestOneDriveSuite(t *testing.T) {
|
||||
suite.Run(t, new(OneDriveSuite))
|
||||
}
|
||||
|
||||
func (suite *OneDriveSuite) TestAddOneDriveCommands() {
|
||||
expectUse := oneDriveServiceCommand
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
use string
|
||||
expectUse string
|
||||
expectShort string
|
||||
expectRunE func(*cobra.Command, []string) error
|
||||
}{
|
||||
{"restore onedrive", restoreCommand, expectUse, oneDriveRestoreCmd().Short, restoreOneDriveCmd},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
cmd := &cobra.Command{Use: test.use}
|
||||
|
||||
c := addOneDriveCommands(cmd)
|
||||
require.NotNil(t, c)
|
||||
|
||||
cmds := cmd.Commands()
|
||||
require.Len(t, cmds, 1)
|
||||
|
||||
child := cmds[0]
|
||||
assert.Equal(t, test.expectUse, child.Use)
|
||||
assert.Equal(t, test.expectShort, child.Short)
|
||||
tester.AreSameFunc(t, test.expectRunE, child.RunE)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ import (
|
||||
|
||||
var restoreCommands = []func(parent *cobra.Command) *cobra.Command{
|
||||
addExchangeCommands,
|
||||
addOneDriveCommands,
|
||||
}
|
||||
|
||||
// AddCommands attaches all `corso restore * *` commands to the parent.
|
||||
|
||||
14
src/cli/utils/onedrive.go
Normal file
14
src/cli/utils/onedrive.go
Normal file
@ -0,0 +1,14 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// ValidateOneDriveRestoreFlags checks common flags for correctness and interdependencies
|
||||
func ValidateOneDriveRestoreFlags(backupID string) error {
|
||||
if len(backupID) == 0 {
|
||||
return errors.New("a backup ID is required")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"github.com/alcionai/corso/src/internal/path"
|
||||
"github.com/alcionai/corso/src/internal/stats"
|
||||
"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/logger"
|
||||
"github.com/alcionai/corso/src/pkg/selectors"
|
||||
@ -118,16 +119,27 @@ func (op *RestoreOperation) Run(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
er, err := op.Selectors.ToExchangeRestore()
|
||||
if err != nil {
|
||||
opStats.readErr = err
|
||||
return err
|
||||
}
|
||||
var fds *details.Details
|
||||
|
||||
// format the details and retrieve the items from kopia
|
||||
fds := er.Reduce(ctx, d)
|
||||
if len(fds.Entries) == 0 {
|
||||
return errors.New("nothing to restore: no items in the backup match the provided selectors")
|
||||
switch op.Selectors.Service {
|
||||
case selectors.ServiceExchange:
|
||||
er, err := op.Selectors.ToExchangeRestore()
|
||||
if err != nil {
|
||||
opStats.readErr = err
|
||||
return err
|
||||
}
|
||||
|
||||
// format the details and retrieve the items from kopia
|
||||
fds = er.Reduce(ctx, d)
|
||||
if len(fds.Entries) == 0 {
|
||||
return errors.New("nothing to restore: no items in the backup match the provided selectors")
|
||||
}
|
||||
|
||||
case selectors.ServiceOneDrive:
|
||||
// TODO: Reduce `details` here when we add support for OneDrive restore filters
|
||||
fds = d
|
||||
default:
|
||||
return errors.Errorf("Service %s not supported", op.Selectors.Service)
|
||||
}
|
||||
|
||||
fdsPaths := fds.Paths()
|
||||
|
||||
@ -22,6 +22,13 @@ type (
|
||||
OneDriveBackup struct {
|
||||
oneDrive
|
||||
}
|
||||
|
||||
// OneDriveRestorep provides an api for selecting
|
||||
// data scopes applicable to the OneDrive service,
|
||||
// plus restore-specific methods.
|
||||
OneDriveRestore struct {
|
||||
oneDrive
|
||||
}
|
||||
)
|
||||
|
||||
// NewOneDriveBackup produces a new Selector with the service set to ServiceOneDrive.
|
||||
@ -47,6 +54,29 @@ func (s Selector) ToOneDriveBackup() (*OneDriveBackup, error) {
|
||||
return &src, nil
|
||||
}
|
||||
|
||||
// NewOneDriveRestore produces a new Selector with the service set to ServiceOneDrive.
|
||||
func NewOneDriveRestore() *OneDriveRestore {
|
||||
src := OneDriveRestore{
|
||||
oneDrive{
|
||||
newSelector(ServiceOneDrive),
|
||||
},
|
||||
}
|
||||
|
||||
return &src
|
||||
}
|
||||
|
||||
// ToOneDriveRestore transforms the generic selector into an OneDriveRestore.
|
||||
// Errors if the service defined by the selector is not ServiceOneDrive.
|
||||
func (s Selector) ToOneDriveRestore() (*OneDriveRestore, error) {
|
||||
if s.Service != ServiceOneDrive {
|
||||
return nil, badCastErr(ServiceOneDrive, s.Service)
|
||||
}
|
||||
|
||||
src := OneDriveRestore{oneDrive{s}}
|
||||
|
||||
return &src, nil
|
||||
}
|
||||
|
||||
// Printable creates the minimized display of a selector, formatted for human readability.
|
||||
func (s oneDrive) Printable() Printable {
|
||||
return toPrintable[OneDriveScope](s.Selector)
|
||||
|
||||
@ -157,3 +157,20 @@ func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Exclude_Users() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *OneDriveSelectorSuite) TestNewOneDriveRestore() {
|
||||
t := suite.T()
|
||||
or := NewOneDriveRestore()
|
||||
assert.Equal(t, or.Service, ServiceOneDrive)
|
||||
assert.NotZero(t, or.Scopes())
|
||||
}
|
||||
|
||||
func (suite *OneDriveSelectorSuite) TestToOneDriveRestore() {
|
||||
t := suite.T()
|
||||
eb := NewOneDriveRestore()
|
||||
s := eb.Selector
|
||||
or, err := s.ToOneDriveRestore()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, or.Service, ServiceOneDrive)
|
||||
assert.NotZero(t, or.Scopes())
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user