A few high-level things of note: * things will no longer match on folder ID. Folder IDs weren't displayed to the user via CLI and SDK consumers have no insight into folder IDs so this shouldn't be an issue * OneDrive and SharePoint match on ParentPath (derived from LocationRef). ParentPath *does not* include root: in the path Not matching on folder ID should be the only user-visible change in this PR First commit contains the required logic changes. All other changes are test updates --- #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [x] ⛔ No #### Type of change - [ ] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [x] 🤖 Supportability/Tests - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup #### Issue(s) * closes #3194 #### Test Plan - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
454 lines
11 KiB
Go
454 lines
11 KiB
Go
package selectors
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/alcionai/clues"
|
|
"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/internal/tester"
|
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
|
"github.com/alcionai/corso/src/pkg/fault"
|
|
"github.com/alcionai/corso/src/pkg/path"
|
|
)
|
|
|
|
type OneDriveSelectorSuite struct {
|
|
tester.Suite
|
|
}
|
|
|
|
func TestOneDriveSelectorSuite(t *testing.T) {
|
|
suite.Run(t, &OneDriveSelectorSuite{Suite: tester.NewUnitSuite(t)})
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestNewOneDriveBackup() {
|
|
t := suite.T()
|
|
ob := NewOneDriveBackup(Any())
|
|
assert.Equal(t, ob.Service, ServiceOneDrive)
|
|
assert.NotZero(t, ob.Scopes())
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestToOneDriveBackup() {
|
|
t := suite.T()
|
|
ob := NewOneDriveBackup(Any())
|
|
s := ob.Selector
|
|
ob, err := s.ToOneDriveBackup()
|
|
require.NoError(t, err, clues.ToCore(err))
|
|
assert.Equal(t, ob.Service, ServiceOneDrive)
|
|
assert.NotZero(t, ob.Scopes())
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestOneDriveSelector_AllData() {
|
|
t := suite.T()
|
|
|
|
var (
|
|
users = []string{"u1", "u2"}
|
|
sel = NewOneDriveBackup(users)
|
|
allScopes = sel.AllData()
|
|
)
|
|
|
|
assert.ElementsMatch(t, users, sel.DiscreteResourceOwners())
|
|
|
|
// Initialize the selector Include, Exclude, Filter
|
|
sel.Exclude(allScopes)
|
|
sel.Include(allScopes)
|
|
sel.Filter(allScopes)
|
|
|
|
table := []struct {
|
|
name string
|
|
scopesToCheck []scope
|
|
}{
|
|
{"Include Scopes", sel.Includes},
|
|
{"Exclude Scopes", sel.Excludes},
|
|
{"info scopes", sel.Filters},
|
|
}
|
|
for _, test := range table {
|
|
suite.Run(test.name, func() {
|
|
t := suite.T()
|
|
|
|
require.Len(t, test.scopesToCheck, 1)
|
|
for _, scope := range test.scopesToCheck {
|
|
scopeMustHave(
|
|
t,
|
|
OneDriveScope(scope),
|
|
map[categorizer][]string{
|
|
OneDriveItem: Any(),
|
|
OneDriveFolder: Any(),
|
|
},
|
|
)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Include_AllData() {
|
|
t := suite.T()
|
|
|
|
const (
|
|
u1 = "u1"
|
|
u2 = "u2"
|
|
)
|
|
|
|
var (
|
|
users = []string{u1, u2}
|
|
sel = NewOneDriveBackup(users)
|
|
allScopes = sel.AllData()
|
|
)
|
|
|
|
sel.Include(allScopes)
|
|
scopes := sel.Includes
|
|
require.Len(t, scopes, 1)
|
|
|
|
for _, sc := range scopes {
|
|
scopeMustHave(
|
|
t,
|
|
OneDriveScope(sc),
|
|
map[categorizer][]string{
|
|
OneDriveItem: Any(),
|
|
OneDriveFolder: Any(),
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Exclude_AllData() {
|
|
t := suite.T()
|
|
|
|
const (
|
|
u1 = "u1"
|
|
u2 = "u2"
|
|
)
|
|
|
|
var (
|
|
users = []string{u1, u2}
|
|
sel = NewOneDriveBackup(users)
|
|
allScopes = sel.AllData()
|
|
)
|
|
|
|
sel.Exclude(allScopes)
|
|
scopes := sel.Excludes
|
|
require.Len(t, scopes, 1)
|
|
|
|
for _, sc := range scopes {
|
|
scopeMustHave(
|
|
t,
|
|
OneDriveScope(sc),
|
|
map[categorizer][]string{
|
|
OneDriveItem: Any(),
|
|
OneDriveFolder: Any(),
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestNewOneDriveRestore() {
|
|
t := suite.T()
|
|
or := NewOneDriveRestore(Any())
|
|
assert.Equal(t, or.Service, ServiceOneDrive)
|
|
assert.NotZero(t, or.Scopes())
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestToOneDriveRestore() {
|
|
t := suite.T()
|
|
eb := NewOneDriveRestore(Any())
|
|
s := eb.Selector
|
|
or, err := s.ToOneDriveRestore()
|
|
require.NoError(t, err, clues.ToCore(err))
|
|
assert.Equal(t, or.Service, ServiceOneDrive)
|
|
assert.NotZero(t, or.Scopes())
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() {
|
|
var (
|
|
file = stubRepoRef(
|
|
path.OneDriveService,
|
|
path.FilesCategory,
|
|
"uid",
|
|
"drive/driveID/root:/folderA.d/folderB.d",
|
|
"file")
|
|
fileParent = "folderA/folderB"
|
|
file2 = stubRepoRef(
|
|
path.OneDriveService,
|
|
path.FilesCategory,
|
|
"uid",
|
|
"drive/driveID/root:/folderA.d/folderC.d",
|
|
"file2")
|
|
fileParent2 = "folderA/folderC"
|
|
file3 = stubRepoRef(
|
|
path.OneDriveService,
|
|
path.FilesCategory,
|
|
"uid",
|
|
"drive/driveID/root:/folderD.d/folderE.d",
|
|
"file3")
|
|
fileParent3 = "folderD/folderE"
|
|
)
|
|
|
|
deets := &details.Details{
|
|
DetailsModel: details.DetailsModel{
|
|
Entries: []details.DetailsEntry{
|
|
{
|
|
RepoRef: file,
|
|
ItemRef: "file",
|
|
ItemInfo: details.ItemInfo{
|
|
OneDrive: &details.OneDriveInfo{
|
|
ItemType: details.OneDriveItem,
|
|
ItemName: "fileName",
|
|
ParentPath: fileParent,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
RepoRef: file2,
|
|
ItemRef: "file2",
|
|
ItemInfo: details.ItemInfo{
|
|
OneDrive: &details.OneDriveInfo{
|
|
ItemType: details.OneDriveItem,
|
|
ItemName: "fileName2",
|
|
ParentPath: fileParent2,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
RepoRef: file3,
|
|
// item ref intentionally blank to assert fallback case
|
|
ItemInfo: details.ItemInfo{
|
|
OneDrive: &details.OneDriveInfo{
|
|
ItemType: details.OneDriveItem,
|
|
ItemName: "fileName3",
|
|
ParentPath: fileParent3,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
arr := func(s ...string) []string {
|
|
return s
|
|
}
|
|
|
|
table := []struct {
|
|
name string
|
|
makeSelector func() *OneDriveRestore
|
|
expect []string
|
|
cfg Config
|
|
}{
|
|
{
|
|
name: "all",
|
|
makeSelector: func() *OneDriveRestore {
|
|
odr := NewOneDriveRestore(Any())
|
|
odr.Include(odr.AllData())
|
|
return odr
|
|
},
|
|
expect: arr(file, file2, file3),
|
|
},
|
|
{
|
|
name: "only match file",
|
|
makeSelector: func() *OneDriveRestore {
|
|
odr := NewOneDriveRestore(Any())
|
|
odr.Include(odr.Items(Any(), []string{"file2"}))
|
|
return odr
|
|
},
|
|
expect: arr(file2),
|
|
},
|
|
{
|
|
name: "id doesn't match name",
|
|
makeSelector: func() *OneDriveRestore {
|
|
odr := NewOneDriveRestore(Any())
|
|
odr.Include(odr.Items(Any(), []string{"file2"}))
|
|
return odr
|
|
},
|
|
expect: []string{},
|
|
cfg: Config{OnlyMatchItemNames: true},
|
|
},
|
|
{
|
|
name: "only match file name",
|
|
makeSelector: func() *OneDriveRestore {
|
|
odr := NewOneDriveRestore(Any())
|
|
odr.Include(odr.Items(Any(), []string{"fileName2"}))
|
|
return odr
|
|
},
|
|
expect: arr(file2),
|
|
cfg: Config{OnlyMatchItemNames: true},
|
|
},
|
|
{
|
|
name: "name doesn't match id",
|
|
makeSelector: func() *OneDriveRestore {
|
|
odr := NewOneDriveRestore(Any())
|
|
odr.Include(odr.Items(Any(), []string{"fileName2"}))
|
|
return odr
|
|
},
|
|
expect: []string{},
|
|
},
|
|
{
|
|
name: "only match folder",
|
|
makeSelector: func() *OneDriveRestore {
|
|
odr := NewOneDriveRestore([]string{"uid"})
|
|
odr.Include(odr.Folders([]string{"folderA/folderB", "folderA/folderC"}))
|
|
return odr
|
|
},
|
|
expect: arr(file, file2),
|
|
},
|
|
}
|
|
for _, test := range table {
|
|
suite.Run(test.name, func() {
|
|
t := suite.T()
|
|
|
|
ctx, flush := tester.NewContext()
|
|
defer flush()
|
|
|
|
sel := test.makeSelector()
|
|
sel.Configure(test.cfg)
|
|
results := sel.Reduce(ctx, deets, fault.New(true))
|
|
paths := results.Paths()
|
|
assert.Equal(t, test.expect, paths)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestOneDriveCategory_PathValues() {
|
|
t := suite.T()
|
|
|
|
fileName := "file"
|
|
fileID := fileName + "-id"
|
|
shortRef := "short"
|
|
elems := []string{"drive", "driveID", "root:", "dir1.d", "dir2.d", fileID}
|
|
|
|
filePath, err := path.Build("tenant", "user", path.OneDriveService, path.FilesCategory, true, elems...)
|
|
require.NoError(t, err, clues.ToCore(err))
|
|
|
|
fileLoc := path.Builder{}.Append("dir1", "dir2")
|
|
|
|
table := []struct {
|
|
name string
|
|
pathElems []string
|
|
expected map[categorizer][]string
|
|
cfg Config
|
|
}{
|
|
{
|
|
name: "items",
|
|
pathElems: elems,
|
|
expected: map[categorizer][]string{
|
|
OneDriveFolder: {"dir1/dir2"},
|
|
OneDriveItem: {fileID, shortRef},
|
|
},
|
|
cfg: Config{},
|
|
},
|
|
{
|
|
name: "items w/ name",
|
|
pathElems: elems,
|
|
expected: map[categorizer][]string{
|
|
OneDriveFolder: {"dir1/dir2"},
|
|
OneDriveItem: {fileName, shortRef},
|
|
},
|
|
cfg: Config{OnlyMatchItemNames: true},
|
|
},
|
|
}
|
|
|
|
for _, test := range table {
|
|
suite.Run(test.name, func() {
|
|
t := suite.T()
|
|
|
|
itemPath, err := path.Build(
|
|
"tenant",
|
|
"site",
|
|
path.OneDriveService,
|
|
path.FilesCategory,
|
|
true,
|
|
test.pathElems...)
|
|
require.NoError(t, err, clues.ToCore(err))
|
|
|
|
ent := details.DetailsEntry{
|
|
RepoRef: filePath.String(),
|
|
ShortRef: shortRef,
|
|
ItemRef: fileID,
|
|
ItemInfo: details.ItemInfo{
|
|
OneDrive: &details.OneDriveInfo{
|
|
ItemName: fileName,
|
|
ParentPath: fileLoc.String(),
|
|
},
|
|
},
|
|
}
|
|
|
|
pv, err := OneDriveItem.pathValues(itemPath, ent, test.cfg)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, test.expected, pv)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestOneDriveScope_MatchesInfo() {
|
|
ods := NewOneDriveRestore(Any())
|
|
|
|
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,
|
|
Owner: "user@email.com",
|
|
Created: now,
|
|
Modified: 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.Run(test.name, func() {
|
|
t := suite.T()
|
|
|
|
scopes := setScopesToDefault(test.scope)
|
|
for _, scope := range scopes {
|
|
test.expect(t, scope.matchesInfo(itemInfo))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *OneDriveSelectorSuite) TestCategory_PathType() {
|
|
table := []struct {
|
|
cat oneDriveCategory
|
|
pathType path.CategoryType
|
|
}{
|
|
{OneDriveCategoryUnknown, path.UnknownCategory},
|
|
{OneDriveUser, path.UnknownCategory},
|
|
{OneDriveItem, path.FilesCategory},
|
|
{OneDriveFolder, path.FilesCategory},
|
|
{FileInfoCreatedAfter, path.FilesCategory},
|
|
{FileInfoCreatedBefore, path.FilesCategory},
|
|
{FileInfoModifiedAfter, path.FilesCategory},
|
|
{FileInfoModifiedBefore, path.FilesCategory},
|
|
}
|
|
for _, test := range table {
|
|
suite.Run(test.cat.String(), func() {
|
|
assert.Equal(suite.T(), test.pathType, test.cat.PathType())
|
|
})
|
|
}
|
|
}
|