Use selectors in OneDrive CLI (#996)
## Description Adds the following selectors to OneDrive details/restore : - `file-name`, `folder`, `file-created-after`, `file-created-before`, `file-modified-after`, `file-modified-before` Also includes a change where we remove the `drive/<driveID>/root:` prefix from parent path entries in details. This is to improve readability. We will add drive back as a separate item in details if needed later. ## Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🐹 Trivial/Minor ## Issue(s) * #627 ## Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
88af7f9b7c
commit
03bb63f52d
@ -1,6 +1,8 @@
|
||||
package backup
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
@ -11,6 +13,7 @@ import (
|
||||
"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/backup/details"
|
||||
"github.com/alcionai/corso/src/pkg/repository"
|
||||
"github.com/alcionai/corso/src/pkg/selectors"
|
||||
)
|
||||
@ -21,6 +24,16 @@ import (
|
||||
|
||||
const oneDriveServiceCommand = "onedrive"
|
||||
|
||||
var (
|
||||
folderPaths []string
|
||||
fileNames []string
|
||||
|
||||
fileCreatedAfter string
|
||||
fileCreatedBefore string
|
||||
fileModifiedAfter string
|
||||
fileModifiedBefore string
|
||||
)
|
||||
|
||||
// called by backup.go to map parent subcommands to provider-specific handling.
|
||||
func addOneDriveCommands(parent *cobra.Command) *cobra.Command {
|
||||
var (
|
||||
@ -44,6 +57,38 @@ func addOneDriveCommands(parent *cobra.Command) *cobra.Command {
|
||||
fs.StringVar(&backupID, "backup", "", "ID of the backup containing the details to be shown")
|
||||
cobra.CheckErr(c.MarkFlagRequired("backup"))
|
||||
|
||||
// onedrive hierarchy flags
|
||||
|
||||
fs.StringSliceVar(
|
||||
&folderPaths,
|
||||
"folder", nil,
|
||||
"Select backup details by OneDrive folder; defaults to root")
|
||||
|
||||
fs.StringSliceVar(
|
||||
&fileNames,
|
||||
"file-name", nil,
|
||||
"Select backup details by OneDrive file name")
|
||||
|
||||
// onedrive info flags
|
||||
|
||||
fs.StringVar(
|
||||
&fileCreatedAfter,
|
||||
"file-created-after", "",
|
||||
"Select files created after this datetime")
|
||||
fs.StringVar(
|
||||
&fileCreatedBefore,
|
||||
"file-created-before", "",
|
||||
"Select files created before this datetime")
|
||||
|
||||
fs.StringVar(
|
||||
&fileModifiedAfter,
|
||||
"file-modified-after", "",
|
||||
"Select files modified after this datetime")
|
||||
fs.StringVar(
|
||||
&fileModifiedBefore,
|
||||
"file-modified-before", "",
|
||||
"Select files modified before this datetime")
|
||||
|
||||
case deleteCommand:
|
||||
c, fs = utils.AddCommand(parent, oneDriveDeleteCmd())
|
||||
fs.StringVar(&backupID, "backup", "", "ID of the backup containing the details to be shown")
|
||||
@ -202,18 +247,56 @@ func detailsOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||
|
||||
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"))
|
||||
opts := utils.OneDriveOpts{
|
||||
Users: user,
|
||||
Paths: folderPaths,
|
||||
Names: fileNames,
|
||||
CreatedAfter: fileCreatedAfter,
|
||||
CreatedBefore: fileCreatedBefore,
|
||||
ModifiedAfter: fileModifiedAfter,
|
||||
ModifiedBefore: fileModifiedBefore,
|
||||
}
|
||||
|
||||
// TODO: Support selectors and filters
|
||||
ds, err := runDetailsOneDriveCmd(ctx, r, backupID, opts)
|
||||
if err != nil {
|
||||
return Only(ctx, err)
|
||||
}
|
||||
|
||||
if len(ds.Entries) == 0 {
|
||||
Info(ctx, selectors.ErrorNoMatchingItems)
|
||||
return nil
|
||||
}
|
||||
|
||||
ds.PrintEntries(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// runDetailsOneDriveCmd actually performs the lookup in backup details. Assumes
|
||||
// len(backupID) > 0.
|
||||
func runDetailsOneDriveCmd(
|
||||
ctx context.Context,
|
||||
r repository.BackupGetter,
|
||||
backupID string,
|
||||
opts utils.OneDriveOpts,
|
||||
) (*details.Details, error) {
|
||||
d, _, err := r.BackupDetails(ctx, backupID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to get backup details in the repository")
|
||||
}
|
||||
|
||||
sel := selectors.NewOneDriveRestore()
|
||||
utils.IncludeOneDriveRestoreDataSelectors(sel, opts)
|
||||
utils.FilterOneDriveRestoreInfoSelectors(sel, opts)
|
||||
|
||||
// if no selector flags were specified, get all data in the service.
|
||||
if len(sel.Scopes()) == 0 {
|
||||
sel.Include(sel.Users(selectors.Any()))
|
||||
}
|
||||
|
||||
return sel.Reduce(ctx, d), nil
|
||||
}
|
||||
|
||||
// `corso backup delete onedrive [<flag>...]`
|
||||
func oneDriveDeleteCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
|
||||
@ -15,6 +15,16 @@ import (
|
||||
"github.com/alcionai/corso/src/pkg/selectors"
|
||||
)
|
||||
|
||||
var (
|
||||
folderPaths []string
|
||||
fileNames []string
|
||||
|
||||
fileCreatedAfter string
|
||||
fileCreatedBefore string
|
||||
fileModifiedAfter string
|
||||
fileModifiedBefore string
|
||||
)
|
||||
|
||||
// called by restore.go to map parent subcommands to provider-specific handling.
|
||||
func addOneDriveCommands(parent *cobra.Command) *cobra.Command {
|
||||
var (
|
||||
@ -37,6 +47,38 @@ func addOneDriveCommands(parent *cobra.Command) *cobra.Command {
|
||||
"user", nil,
|
||||
"Restore all data by user ID; accepts "+utils.Wildcard+" to select all users")
|
||||
|
||||
// onedrive hierarchy (path/name) flags
|
||||
|
||||
fs.StringSliceVar(
|
||||
&folderPaths,
|
||||
"folder", nil,
|
||||
"Restore items by OneDrive folder; defaults to root")
|
||||
|
||||
fs.StringSliceVar(
|
||||
&fileNames,
|
||||
"file-name", nil,
|
||||
"Restore items by OneDrive file name")
|
||||
|
||||
// onedrive info flags
|
||||
|
||||
fs.StringVar(
|
||||
&fileCreatedAfter,
|
||||
"file-created-after", "",
|
||||
"Restore files created after this datetime")
|
||||
fs.StringVar(
|
||||
&fileCreatedBefore,
|
||||
"file-created-before", "",
|
||||
"Restore files created before this datetime")
|
||||
|
||||
fs.StringVar(
|
||||
&fileModifiedAfter,
|
||||
"file-modified-after", "",
|
||||
"Restore files modified after this datetime")
|
||||
fs.StringVar(
|
||||
&fileModifiedBefore,
|
||||
"file-modified-before", "",
|
||||
"Restore files modified before this datetime")
|
||||
|
||||
// others
|
||||
options.AddOperationFlags(c)
|
||||
}
|
||||
@ -80,11 +122,20 @@ func restoreOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||
|
||||
defer utils.CloseRepo(ctx, r)
|
||||
|
||||
sel := selectors.NewOneDriveRestore()
|
||||
if user != nil {
|
||||
sel.Include(sel.Users(user))
|
||||
opts := utils.OneDriveOpts{
|
||||
Users: user,
|
||||
Paths: folderPaths,
|
||||
Names: fileNames,
|
||||
CreatedAfter: fileCreatedAfter,
|
||||
CreatedBefore: fileCreatedBefore,
|
||||
ModifiedAfter: fileModifiedAfter,
|
||||
ModifiedBefore: fileModifiedBefore,
|
||||
}
|
||||
|
||||
sel := selectors.NewOneDriveRestore()
|
||||
utils.IncludeOneDriveRestoreDataSelectors(sel, opts)
|
||||
utils.FilterOneDriveRestoreInfoSelectors(sel, opts)
|
||||
|
||||
// if no selector flags were specified, get all data in the service.
|
||||
if len(sel.Scopes()) == 0 {
|
||||
sel.Include(sel.Users(selectors.Any()))
|
||||
|
||||
@ -2,8 +2,20 @@ package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/alcionai/corso/src/pkg/selectors"
|
||||
)
|
||||
|
||||
type OneDriveOpts struct {
|
||||
Users []string
|
||||
Names []string
|
||||
Paths []string
|
||||
CreatedAfter string
|
||||
CreatedBefore string
|
||||
ModifiedAfter string
|
||||
ModifiedBefore string
|
||||
}
|
||||
|
||||
// ValidateOneDriveRestoreFlags checks common flags for correctness and interdependencies
|
||||
func ValidateOneDriveRestoreFlags(backupID string) error {
|
||||
if len(backupID) == 0 {
|
||||
@ -12,3 +24,58 @@ func ValidateOneDriveRestoreFlags(backupID string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddOneDriveFilter adds the scope of the provided values to the selector's
|
||||
// filter set
|
||||
func AddOneDriveFilter(
|
||||
sel *selectors.OneDriveRestore,
|
||||
v string,
|
||||
f func(string) []selectors.OneDriveScope,
|
||||
) {
|
||||
if len(v) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
sel.Filter(f(v))
|
||||
}
|
||||
|
||||
// IncludeOneDriveRestoreDataSelectors builds the common data-selector
|
||||
// inclusions for OneDrive commands.
|
||||
func IncludeOneDriveRestoreDataSelectors(
|
||||
sel *selectors.OneDriveRestore,
|
||||
opts OneDriveOpts,
|
||||
) {
|
||||
if len(opts.Users) == 0 {
|
||||
opts.Users = selectors.Any()
|
||||
}
|
||||
|
||||
lp, ln := len(opts.Paths), len(opts.Names)
|
||||
|
||||
// either scope the request to a set of users
|
||||
if lp+ln == 0 {
|
||||
sel.Include(sel.Users(opts.Users))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if lp == 0 {
|
||||
opts.Paths = selectors.Any()
|
||||
}
|
||||
|
||||
if ln == 0 {
|
||||
opts.Names = selectors.Any()
|
||||
}
|
||||
|
||||
sel.Include(sel.Items(opts.Users, opts.Paths, opts.Names))
|
||||
}
|
||||
|
||||
// FilterOneDriveRestoreInfoSelectors builds the common info-selector filters.
|
||||
func FilterOneDriveRestoreInfoSelectors(
|
||||
sel *selectors.OneDriveRestore,
|
||||
opts OneDriveOpts,
|
||||
) {
|
||||
AddOneDriveFilter(sel, opts.CreatedAfter, sel.CreatedAfter)
|
||||
AddOneDriveFilter(sel, opts.CreatedBefore, sel.CreatedBefore)
|
||||
AddOneDriveFilter(sel, opts.ModifiedAfter, sel.ModifiedAfter)
|
||||
AddOneDriveFilter(sel, opts.ModifiedBefore, sel.ModifiedBefore)
|
||||
}
|
||||
|
||||
@ -111,6 +111,14 @@ func (oc *Collection) populateItems(ctx context.Context) {
|
||||
itemsRead = 0
|
||||
)
|
||||
|
||||
// Retrieve the OneDrive folder path to set later in
|
||||
// `details.OneDriveInfo`
|
||||
parentPathString, err := getDriveFolderPath(oc.folderPath)
|
||||
if err != nil {
|
||||
oc.reportAsCompleted(ctx, 0, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, itemID := range oc.driveItemIDs {
|
||||
// Read the item
|
||||
itemInfo, itemData, err := oc.itemReader(ctx, oc.service, oc.driveID, itemID)
|
||||
@ -126,7 +134,7 @@ func (oc *Collection) populateItems(ctx context.Context) {
|
||||
// Item read successfully, add to collection
|
||||
itemsRead++
|
||||
|
||||
itemInfo.ParentPath = oc.folderPath.String()
|
||||
itemInfo.ParentPath = parentPathString
|
||||
|
||||
oc.data <- &Item{
|
||||
id: itemInfo.ItemName,
|
||||
@ -135,6 +143,10 @@ func (oc *Collection) populateItems(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
oc.reportAsCompleted(ctx, itemsRead, errs)
|
||||
}
|
||||
|
||||
func (oc *Collection) reportAsCompleted(ctx context.Context, itemsRead int, errs error) {
|
||||
close(oc.data)
|
||||
|
||||
status := support.CreateStatus(ctx, support.Backup,
|
||||
|
||||
@ -60,7 +60,9 @@ func (suite *OneDriveCollectionSuite) TestOneDriveCollection() {
|
||||
wg := sync.WaitGroup{}
|
||||
collStatus := support.ConnectorOperationStatus{}
|
||||
|
||||
folderPath, err := getCanonicalPath("dir1/dir2/dir3", "a-tenant", "a-user")
|
||||
folderPath, err := getCanonicalPath("drive/driveID1/root:/dir1/dir2/dir3", "a-tenant", "a-user")
|
||||
require.NoError(t, err)
|
||||
driveFolderPath, err := getDriveFolderPath(folderPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
coll := NewCollection(folderPath, "fakeDriveID", suite, suite.testStatusUpdater(&wg, &collStatus))
|
||||
@ -106,7 +108,7 @@ func (suite *OneDriveCollectionSuite) TestOneDriveCollection() {
|
||||
require.NotNil(t, readItemInfo.Info())
|
||||
require.NotNil(t, readItemInfo.Info().OneDrive)
|
||||
assert.Equal(t, testItemName, readItemInfo.Info().OneDrive.ItemName)
|
||||
assert.Equal(t, folderPath.String(), readItemInfo.Info().OneDrive.ParentPath)
|
||||
assert.Equal(t, driveFolderPath, readItemInfo.Info().OneDrive.ParentPath)
|
||||
}
|
||||
|
||||
func (suite *OneDriveCollectionSuite) TestOneDriveCollectionReadError() {
|
||||
|
||||
@ -82,6 +82,16 @@ func getCanonicalPath(p, tenant, user string) (path.Path, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Returns the path to the folder within the drive (i.e. under `root:`)
|
||||
func getDriveFolderPath(p path.Path) (string, error) {
|
||||
drivePath, err := toOneDrivePath(p)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return path.Builder{}.Append(drivePath.folders...).String(), nil
|
||||
}
|
||||
|
||||
// updateCollections initializes and adds the provided OneDrive items to Collections
|
||||
// A new collection is created for every OneDrive folder (or package)
|
||||
func (c *Collections) updateCollections(ctx context.Context, driveID string, items []models.DriveItemable) error {
|
||||
|
||||
@ -149,12 +149,24 @@ func (op *RestoreOperation) Run(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
case selectors.ServiceOneDrive:
|
||||
// TODO: Reduce `details` here when we add support for OneDrive restore filters
|
||||
fds = d
|
||||
odr, err := op.Selectors.ToOneDriveRestore()
|
||||
if err != nil {
|
||||
opStats.readErr = err
|
||||
return err
|
||||
}
|
||||
|
||||
// format the details and retrieve the items from kopia
|
||||
fds = odr.Reduce(ctx, d)
|
||||
if len(fds.Entries) == 0 {
|
||||
return selectors.ErrorNoMatchingItems
|
||||
}
|
||||
|
||||
default:
|
||||
return errors.Errorf("Service %s not supported", op.Selectors.Service)
|
||||
}
|
||||
|
||||
logger.Ctx(ctx).Infof("Discovered %d items in backup %s to restore", len(fds.Entries), op.BackupID)
|
||||
|
||||
fdsPaths := fds.Paths()
|
||||
paths := make([]path.Path, len(fdsPaths))
|
||||
|
||||
|
||||
@ -3,7 +3,9 @@ package selectors
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common"
|
||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||
"github.com/alcionai/corso/src/pkg/filters"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
)
|
||||
|
||||
@ -202,6 +204,65 @@ func (s *oneDrive) Items(users, folders, items []string) []OneDriveScope {
|
||||
return scopes
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// Filter Factories
|
||||
|
||||
// CreatedAfter produces a OneDrive item created-after filter scope.
|
||||
// Matches any item where the created time is after the timestring.
|
||||
// If the input equals selectors.Any, the scope will match all times.
|
||||
// If the input is empty or selectors.None, the scope will always fail comparisons.
|
||||
func (s *oneDrive) CreatedAfter(timeStrings string) []OneDriveScope {
|
||||
return []OneDriveScope{
|
||||
makeFilterScope[OneDriveScope](
|
||||
OneDriveItem,
|
||||
FileFilterCreatedAfter,
|
||||
[]string{timeStrings},
|
||||
wrapFilter(filters.Less)),
|
||||
}
|
||||
}
|
||||
|
||||
// CreatedBefore produces a OneDrive item created-before filter scope.
|
||||
// Matches any item where the created time is before the timestring.
|
||||
// If the input equals selectors.Any, the scope will match all times.
|
||||
// If the input is empty or selectors.None, the scope will always fail comparisons.
|
||||
func (s *oneDrive) CreatedBefore(timeStrings string) []OneDriveScope {
|
||||
return []OneDriveScope{
|
||||
makeFilterScope[OneDriveScope](
|
||||
OneDriveItem,
|
||||
FileFilterCreatedBefore,
|
||||
[]string{timeStrings},
|
||||
wrapFilter(filters.Greater)),
|
||||
}
|
||||
}
|
||||
|
||||
// ModifiedAfter produces a OneDrive item modified-after filter scope.
|
||||
// Matches any item where the modified time is after the timestring.
|
||||
// If the input equals selectors.Any, the scope will match all times.
|
||||
// If the input is empty or selectors.None, the scope will always fail comparisons.
|
||||
func (s *oneDrive) ModifiedAfter(timeStrings string) []OneDriveScope {
|
||||
return []OneDriveScope{
|
||||
makeFilterScope[OneDriveScope](
|
||||
OneDriveItem,
|
||||
FileFilterModifiedAfter,
|
||||
[]string{timeStrings},
|
||||
wrapFilter(filters.Less)),
|
||||
}
|
||||
}
|
||||
|
||||
// ModifiedBefore produces a OneDrive item modified-before filter scope.
|
||||
// Matches any item where the modified time is before the timestring.
|
||||
// If the input equals selectors.Any, the scope will match all times.
|
||||
// If the input is empty or selectors.None, the scope will always fail comparisons.
|
||||
func (s *oneDrive) ModifiedBefore(timeStrings string) []OneDriveScope {
|
||||
return []OneDriveScope{
|
||||
makeFilterScope[OneDriveScope](
|
||||
OneDriveItem,
|
||||
FileFilterModifiedBefore,
|
||||
[]string{timeStrings},
|
||||
wrapFilter(filters.Greater)),
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Categories
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -219,6 +280,12 @@ const (
|
||||
OneDriveUser oneDriveCategory = "OneDriveUser"
|
||||
OneDriveItem oneDriveCategory = "OneDriveItem"
|
||||
OneDriveFolder oneDriveCategory = "OneDriveFolder"
|
||||
|
||||
// filterable topics identified by OneDrive
|
||||
FileFilterCreatedAfter oneDriveCategory = "FileFilterCreatedAfter"
|
||||
FileFilterCreatedBefore oneDriveCategory = "FileFilterCreatedBefore"
|
||||
FileFilterModifiedAfter oneDriveCategory = "FileFilterModifiedAfter"
|
||||
FileFilterModifiedBefore oneDriveCategory = "FileFilterModifiedBefore"
|
||||
)
|
||||
|
||||
// oneDrivePathSet describes the category type keys used in OneDrive paths.
|
||||
@ -240,7 +307,9 @@ func (c oneDriveCategory) String() string {
|
||||
// Ex: ServiceUser.leafCat() => ServiceUser
|
||||
func (c oneDriveCategory) leafCat() categorizer {
|
||||
switch c {
|
||||
case OneDriveFolder, OneDriveItem:
|
||||
case OneDriveFolder, OneDriveItem,
|
||||
FileFilterCreatedAfter, FileFilterCreatedBefore,
|
||||
FileFilterModifiedAfter, FileFilterModifiedBefore:
|
||||
return OneDriveItem
|
||||
}
|
||||
|
||||
@ -269,9 +338,12 @@ func (c oneDriveCategory) isLeaf() bool {
|
||||
// [tenantID, service, userPN, category, folder, fileID]
|
||||
// => {odUser: userPN, odFolder: folder, odFileID: fileID}
|
||||
func (c oneDriveCategory) pathValues(p path.Path) map[categorizer]string {
|
||||
// Ignore `drives/<driveID>/root:` for folder comparison
|
||||
folder := path.Builder{}.Append(p.Folders()...).PopFront().PopFront().PopFront().String()
|
||||
|
||||
return map[categorizer]string{
|
||||
OneDriveUser: p.ResourceOwner(),
|
||||
OneDriveFolder: p.Folder(), // TODO: Should we filter out the DriveID here?
|
||||
OneDriveFolder: folder,
|
||||
OneDriveItem: p.Item(),
|
||||
}
|
||||
}
|
||||
@ -360,31 +432,18 @@ func (s OneDriveScope) matchesInfo(dii details.ItemInfo) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// the scope must define targets to match on
|
||||
filterCat := s.FilterCategory()
|
||||
targets := s.Get(filterCat)
|
||||
|
||||
if len(targets) == 0 {
|
||||
return false
|
||||
i := ""
|
||||
|
||||
switch filterCat {
|
||||
case FileFilterCreatedAfter, FileFilterCreatedBefore:
|
||||
i = common.FormatTime(info.Created)
|
||||
case FileFilterModifiedAfter, FileFilterModifiedBefore:
|
||||
i = common.FormatTime(info.LastModified)
|
||||
}
|
||||
|
||||
if targets[0] == AnyTgt {
|
||||
return true
|
||||
}
|
||||
|
||||
if targets[0] == NoneTgt {
|
||||
return false
|
||||
}
|
||||
// any of the targets for a given info filter may succeed.
|
||||
for _, target := range targets {
|
||||
switch filterCat {
|
||||
// TODO: populate oneDrive filter checks
|
||||
default:
|
||||
return target != NoneTgt
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return s.Matches(filterCat, i)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@ -3,11 +3,13 @@ package selectors
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common"
|
||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
)
|
||||
@ -181,9 +183,9 @@ func (suite *OneDriveSelectorSuite) TestToOneDriveRestore() {
|
||||
|
||||
func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() {
|
||||
var (
|
||||
file = stubRepoRef(path.OneDriveService, path.FilesCategory, "uid", "folderA/folderB", "file")
|
||||
file2 = stubRepoRef(path.OneDriveService, path.FilesCategory, "uid", "folderA/folderC", "file2")
|
||||
file3 = stubRepoRef(path.OneDriveService, path.FilesCategory, "uid", "folderD/folderE", "file3")
|
||||
file = stubRepoRef(path.OneDriveService, path.FilesCategory, "uid", "drive/driveID/root:/folderA/folderB", "file")
|
||||
file2 = stubRepoRef(path.OneDriveService, path.FilesCategory, "uid", "drive/driveID/root:/folderA/folderC", "file2")
|
||||
file3 = stubRepoRef(path.OneDriveService, path.FilesCategory, "uid", "drive/driveID/root:/folderD/folderE", "file3")
|
||||
)
|
||||
|
||||
deets := &details.Details{
|
||||
@ -267,3 +269,67 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *OneDriveSelectorSuite) TestOneDriveCategory_PathValues() {
|
||||
t := suite.T()
|
||||
|
||||
pathBuilder := path.Builder{}.Append("drive", "driveID", "root:", "dir1", "dir2", "file")
|
||||
filePath, err := pathBuilder.ToDataLayerOneDrivePath("tenant", "user", true)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := map[categorizer]string{
|
||||
OneDriveUser: "user",
|
||||
OneDriveFolder: "dir1/dir2",
|
||||
OneDriveItem: "file",
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, OneDriveItem.pathValues(filePath))
|
||||
}
|
||||
|
||||
func (suite *OneDriveSelectorSuite) TestOneDriveScope_MatchesInfo() {
|
||||
ods := NewOneDriveRestore()
|
||||
|
||||
var (
|
||||
epoch = time.Time{}
|
||||
now = time.Now()
|
||||
future = now.Add(1 * time.Minute)
|
||||
)
|
||||
|
||||
itemInfo := details.ItemInfo{
|
||||
OneDrive: &details.OneDriveInfo{
|
||||
ItemType: details.OneDriveItem,
|
||||
ParentPath: "folder1/folder2",
|
||||
ItemName: "file1",
|
||||
Size: 10,
|
||||
Created: now,
|
||||
LastModified: now,
|
||||
},
|
||||
}
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
scope []OneDriveScope
|
||||
expect assert.BoolAssertionFunc
|
||||
}{
|
||||
{"file create after the epoch", ods.CreatedAfter(common.FormatTime(epoch)), assert.True},
|
||||
{"file create after now", ods.CreatedAfter(common.FormatTime(now)), assert.False},
|
||||
{"file create after later", ods.CreatedAfter(common.FormatTime(future)), assert.False},
|
||||
{"file create before future", ods.CreatedBefore(common.FormatTime(future)), assert.True},
|
||||
{"file create before now", ods.CreatedBefore(common.FormatTime(now)), assert.False},
|
||||
{"file create before epoch", ods.CreatedBefore(common.FormatTime(now)), assert.False},
|
||||
{"file modified after the epoch", ods.ModifiedAfter(common.FormatTime(epoch)), assert.True},
|
||||
{"file modified after now", ods.ModifiedAfter(common.FormatTime(now)), assert.False},
|
||||
{"file modified after later", ods.ModifiedAfter(common.FormatTime(future)), assert.False},
|
||||
{"file modified before future", ods.ModifiedBefore(common.FormatTime(future)), assert.True},
|
||||
{"file modified before now", ods.ModifiedBefore(common.FormatTime(now)), assert.False},
|
||||
{"file modified before epoch", ods.ModifiedBefore(common.FormatTime(now)), assert.False},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
scopes := setScopesToDefault(test.scope)
|
||||
for _, scope := range scopes {
|
||||
test.expect(t, scope.matchesInfo(itemInfo))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user