From 754e14d7a6a5102c83f6ab34a6b239bd411d3b0b Mon Sep 17 00:00:00 2001 From: ashmrtn Date: Thu, 27 Apr 2023 15:01:34 -0700 Subject: [PATCH] Don't use RepoRef in selector reduction (#3236) 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? - [ ] :white_check_mark: Yes, it's included - [ ] :clock1: Yes, but in a later PR - [x] :no_entry: No #### Type of change - [ ] :sunflower: Feature - [ ] :bug: Bugfix - [ ] :world_map: Documentation - [x] :robot: Supportability/Tests - [ ] :computer: CI/Deployment - [ ] :broom: Tech Debt/Cleanup #### Issue(s) * closes #3194 #### Test Plan - [ ] :muscle: Manual - [x] :zap: Unit test - [ ] :green_heart: E2E --- src/cli/utils/testdata/opts.go | 32 ++- src/pkg/backup/details/testdata/testdata.go | 295 +++++++++++++------- src/pkg/selectors/example_selectors_test.go | 7 +- src/pkg/selectors/exchange.go | 6 +- src/pkg/selectors/exchange_test.go | 119 +++++--- src/pkg/selectors/onedrive.go | 2 +- src/pkg/selectors/onedrive_test.go | 67 +++-- src/pkg/selectors/selectors_reduce_test.go | 22 +- src/pkg/selectors/sharepoint.go | 20 +- src/pkg/selectors/sharepoint_test.go | 163 +++++++---- 10 files changed, 467 insertions(+), 266 deletions(-) diff --git a/src/cli/utils/testdata/opts.go b/src/cli/utils/testdata/opts.go index 9511f58ab..4018ef19a 100644 --- a/src/cli/utils/testdata/opts.go +++ b/src/cli/utils/testdata/opts.go @@ -138,14 +138,14 @@ var ( Name: "EmailsFolderPrefixMatch", Expected: testdata.ExchangeEmailItems, Opts: utils.ExchangeOpts{ - EmailFolder: []string{testdata.ExchangeEmailInboxPath.Folder(false)}, + EmailFolder: []string{testdata.ExchangeEmailInboxPath.FolderLocation()}, }, }, { Name: "EmailsFolderPrefixMatchTrailingSlash", Expected: testdata.ExchangeEmailItems, Opts: utils.ExchangeOpts{ - EmailFolder: []string{testdata.ExchangeEmailInboxPath.Folder(false) + "/"}, + EmailFolder: []string{testdata.ExchangeEmailInboxPath.FolderLocation() + "/"}, }, }, { @@ -155,7 +155,7 @@ var ( testdata.ExchangeEmailItems[2], }, Opts: utils.ExchangeOpts{ - EmailFolder: []string{testdata.ExchangeEmailBasePath2.Folder(false)}, + EmailFolder: []string{testdata.ExchangeEmailBasePath2.FolderLocation()}, }, }, { @@ -165,7 +165,7 @@ var ( testdata.ExchangeEmailItems[2], }, Opts: utils.ExchangeOpts{ - EmailFolder: []string{testdata.ExchangeEmailBasePath2.Folder(false) + "/"}, + EmailFolder: []string{testdata.ExchangeEmailBasePath2.FolderLocation() + "/"}, }, }, { @@ -209,7 +209,7 @@ var ( Name: "MailShortRef", Expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]}, Opts: utils.ExchangeOpts{ - Email: []string{testdata.ExchangeEmailItemPath1.ShortRef()}, + Email: []string{testdata.ExchangeEmailItemPath1.RR.ShortRef()}, }, }, { @@ -220,8 +220,8 @@ var ( }, Opts: utils.ExchangeOpts{ Email: []string{ - testdata.ExchangeEmailItemPath1.ShortRef(), - testdata.ExchangeEmailItemPath2.ShortRef(), + testdata.ExchangeEmailItemPath1.RR.ShortRef(), + testdata.ExchangeEmailItemPath2.RR.ShortRef(), }, }, }, @@ -248,8 +248,8 @@ var ( testdata.ExchangeEventsItems[0], }, Opts: utils.ExchangeOpts{ - Email: []string{testdata.ExchangeEmailItemPath1.ShortRef()}, - Event: []string{testdata.ExchangeEventsItemPath1.ShortRef()}, + Email: []string{testdata.ExchangeEmailItemPath1.RR.ShortRef()}, + Event: []string{testdata.ExchangeEventsItemPath1.RR.ShortRef()}, }, }, } @@ -375,6 +375,13 @@ var ( FolderPath: []string{testdata.OneDriveFolderFolder + "/"}, }, }, + { + Name: "FolderRepoRefMatchesNothing", + Expected: []details.DetailsEntry{}, + Opts: utils.OneDriveOpts{ + FolderPath: []string{testdata.OneDriveFolderPath.RR.Folder(true)}, + }, + }, { Name: "ShortRef", Expected: []details.DetailsEntry{ @@ -494,6 +501,13 @@ var ( FolderPath: []string{testdata.SharePointLibraryFolder + "/"}, }, }, + { + Name: "FolderRepoRefMatchesNothing", + Expected: []details.DetailsEntry{}, + Opts: utils.SharePointOpts{ + FolderPath: []string{testdata.SharePointLibraryPath.RR.Folder(true)}, + }, + }, { Name: "ShortRef", Expected: []details.DetailsEntry{ diff --git a/src/pkg/backup/details/testdata/testdata.go b/src/pkg/backup/details/testdata/testdata.go index d51937abd..4e4b02d7c 100644 --- a/src/pkg/backup/details/testdata/testdata.go +++ b/src/pkg/backup/details/testdata/testdata.go @@ -1,7 +1,7 @@ package testdata import ( - stdpath "path" + "strings" "time" "github.com/alcionai/corso/src/pkg/backup/details" @@ -33,7 +33,97 @@ func mustAppendPath(p path.Path, newElement string, isItem bool) path.Path { return newP } +func locFromRepo(rr path.Path, isItem bool) *path.Builder { + loc := &path.Builder{} + + for _, e := range rr.Folders() { + loc = loc.Append(strings.TrimSuffix(e, folderSuffix)) + } + + if rr.Service() == path.OneDriveService || rr.Category() == path.LibrariesCategory { + loc = loc.PopFront() + } + + // Folders don't have their final element in the location. + if !isItem { + loc = loc.Dir() + } + + return loc +} + +type repoRefAndLocRef struct { + RR path.Path + loc *path.Builder +} + +func (p repoRefAndLocRef) mustAppend(newElement string, isItem bool) repoRefAndLocRef { + e := newElement + folderSuffix + + if isItem { + e = newElement + fileSuffix + } + + res := repoRefAndLocRef{ + RR: mustAppendPath(p.RR, e, isItem), + } + + res.loc = locFromRepo(res.RR, isItem) + + return res +} + +func (p repoRefAndLocRef) ItemLocation() string { + return strings.TrimSuffix(p.RR.Item(), fileSuffix) +} + +func (p repoRefAndLocRef) FolderLocation() string { + lastElem := p.RR.ToBuilder().LastElem() + + if len(p.RR.Item()) > 0 { + f := p.RR.Folders() + lastElem = f[len(f)-2] + } + + return p.loc.Append(strings.TrimSuffix(lastElem, folderSuffix)).String() +} + +func mustPathRep(ref string, isItem bool) repoRefAndLocRef { + res := repoRefAndLocRef{} + tmp := mustParsePath(ref, isItem) + + // Now append stuff to the RepoRef elements so we have distinct LocationRef + // and RepoRef elements to simulate using IDs in the path instead of display + // names. + rrPB := &path.Builder{} + for _, e := range tmp.Folders() { + rrPB = rrPB.Append(e + folderSuffix) + } + + if isItem { + rrPB = rrPB.Append(tmp.Item() + fileSuffix) + } + + rr, err := rrPB.ToDataLayerPath( + tmp.Tenant(), + tmp.ResourceOwner(), + tmp.Service(), + tmp.Category(), + isItem) + if err != nil { + panic(err) + } + + res.RR = rr + res.loc = locFromRepo(rr, isItem) + + return res +} + const ( + folderSuffix = ".d" + fileSuffix = ".f" + ItemName1 = "item1" ItemName2 = "item2" ItemName3 = "item3" @@ -47,20 +137,21 @@ var ( Time3 = time.Date(2023, 9, 21, 10, 0, 0, 0, time.UTC) Time4 = time.Date(2023, 10, 21, 10, 0, 0, 0, time.UTC) - ExchangeEmailInboxPath = mustParsePath("tenant-id/exchange/user-id/email/Inbox", false) - ExchangeEmailBasePath = mustAppendPath(ExchangeEmailInboxPath, "subfolder", false) - ExchangeEmailBasePath2 = mustAppendPath(ExchangeEmailInboxPath, "othersubfolder/", false) - ExchangeEmailBasePath3 = mustAppendPath(ExchangeEmailBasePath2, "subsubfolder", false) - ExchangeEmailItemPath1 = mustAppendPath(ExchangeEmailBasePath, ItemName1, true) - ExchangeEmailItemPath2 = mustAppendPath(ExchangeEmailBasePath2, ItemName2, true) - ExchangeEmailItemPath3 = mustAppendPath(ExchangeEmailBasePath3, ItemName3, true) + ExchangeEmailInboxPath = mustPathRep("tenant-id/exchange/user-id/email/Inbox", false) + ExchangeEmailBasePath = ExchangeEmailInboxPath.mustAppend("subfolder", false) + ExchangeEmailBasePath2 = ExchangeEmailInboxPath.mustAppend("othersubfolder/", false) + ExchangeEmailBasePath3 = ExchangeEmailBasePath2.mustAppend("subsubfolder", false) + ExchangeEmailItemPath1 = ExchangeEmailBasePath.mustAppend(ItemName1, true) + ExchangeEmailItemPath2 = ExchangeEmailBasePath2.mustAppend(ItemName2, true) + ExchangeEmailItemPath3 = ExchangeEmailBasePath3.mustAppend(ItemName3, true) ExchangeEmailItems = []details.DetailsEntry{ { - RepoRef: ExchangeEmailItemPath1.String(), - ShortRef: ExchangeEmailItemPath1.ShortRef(), - ParentRef: ExchangeEmailItemPath1.ToBuilder().Dir().ShortRef(), - ItemRef: ExchangeEmailItemPath1.Item(), + RepoRef: ExchangeEmailItemPath1.RR.String(), + ShortRef: ExchangeEmailItemPath1.RR.ShortRef(), + ParentRef: ExchangeEmailItemPath1.RR.ToBuilder().Dir().ShortRef(), + ItemRef: ExchangeEmailItemPath1.ItemLocation(), + LocationRef: ExchangeEmailItemPath1.loc.String(), ItemInfo: details.ItemInfo{ Exchange: &details.ExchangeInfo{ ItemType: details.ExchangeMail, @@ -71,10 +162,11 @@ var ( }, }, { - RepoRef: ExchangeEmailItemPath2.String(), - ShortRef: ExchangeEmailItemPath2.ShortRef(), - ParentRef: ExchangeEmailItemPath2.ToBuilder().Dir().ShortRef(), - ItemRef: ExchangeEmailItemPath2.Item(), + RepoRef: ExchangeEmailItemPath2.RR.String(), + ShortRef: ExchangeEmailItemPath2.RR.ShortRef(), + ParentRef: ExchangeEmailItemPath2.RR.ToBuilder().Dir().ShortRef(), + ItemRef: ExchangeEmailItemPath2.ItemLocation(), + LocationRef: ExchangeEmailItemPath2.loc.String(), ItemInfo: details.ItemInfo{ Exchange: &details.ExchangeInfo{ ItemType: details.ExchangeMail, @@ -85,10 +177,11 @@ var ( }, }, { - RepoRef: ExchangeEmailItemPath3.String(), - ShortRef: ExchangeEmailItemPath3.ShortRef(), - ParentRef: ExchangeEmailItemPath3.ToBuilder().Dir().ShortRef(), - ItemRef: ExchangeEmailItemPath3.Item(), + RepoRef: ExchangeEmailItemPath3.RR.String(), + ShortRef: ExchangeEmailItemPath3.RR.ShortRef(), + ParentRef: ExchangeEmailItemPath3.RR.ToBuilder().Dir().ShortRef(), + ItemRef: ExchangeEmailItemPath3.ItemLocation(), + LocationRef: ExchangeEmailItemPath3.loc.String(), ItemInfo: details.ItemInfo{ Exchange: &details.ExchangeInfo{ ItemType: details.ExchangeMail, @@ -100,18 +193,19 @@ var ( }, } - ExchangeContactsRootPath = mustParsePath("tenant-id/exchange/user-id/contacts/contacts", false) - ExchangeContactsBasePath = mustAppendPath(ExchangeContactsRootPath, "contacts", false) - ExchangeContactsBasePath2 = mustAppendPath(ExchangeContactsRootPath, "morecontacts", false) - ExchangeContactsItemPath1 = mustAppendPath(ExchangeContactsBasePath, ItemName1, true) - ExchangeContactsItemPath2 = mustAppendPath(ExchangeContactsBasePath2, ItemName2, true) + ExchangeContactsRootPath = mustPathRep("tenant-id/exchange/user-id/contacts/contacts", false) + ExchangeContactsBasePath = ExchangeContactsRootPath.mustAppend("contacts", false) + ExchangeContactsBasePath2 = ExchangeContactsRootPath.mustAppend("morecontacts", false) + ExchangeContactsItemPath1 = ExchangeContactsBasePath.mustAppend(ItemName1, true) + ExchangeContactsItemPath2 = ExchangeContactsBasePath2.mustAppend(ItemName2, true) ExchangeContactsItems = []details.DetailsEntry{ { - RepoRef: ExchangeContactsItemPath1.String(), - ShortRef: ExchangeContactsItemPath1.ShortRef(), - ParentRef: ExchangeContactsItemPath1.ToBuilder().Dir().ShortRef(), - ItemRef: ExchangeEmailItemPath1.Item(), + RepoRef: ExchangeContactsItemPath1.RR.String(), + ShortRef: ExchangeContactsItemPath1.RR.ShortRef(), + ParentRef: ExchangeContactsItemPath1.RR.ToBuilder().Dir().ShortRef(), + ItemRef: ExchangeContactsItemPath1.ItemLocation(), + LocationRef: ExchangeContactsItemPath1.loc.String(), ItemInfo: details.ItemInfo{ Exchange: &details.ExchangeInfo{ ItemType: details.ExchangeContact, @@ -120,10 +214,11 @@ var ( }, }, { - RepoRef: ExchangeContactsItemPath2.String(), - ShortRef: ExchangeContactsItemPath2.ShortRef(), - ParentRef: ExchangeContactsItemPath2.ToBuilder().Dir().ShortRef(), - ItemRef: ExchangeEmailItemPath2.Item(), + RepoRef: ExchangeContactsItemPath2.RR.String(), + ShortRef: ExchangeContactsItemPath2.RR.ShortRef(), + ParentRef: ExchangeContactsItemPath2.RR.ToBuilder().Dir().ShortRef(), + ItemRef: ExchangeContactsItemPath2.ItemLocation(), + LocationRef: ExchangeContactsItemPath2.loc.String(), ItemInfo: details.ItemInfo{ Exchange: &details.ExchangeInfo{ ItemType: details.ExchangeContact, @@ -133,18 +228,19 @@ var ( }, } - ExchangeEventsRootPath = mustParsePath("tenant-id/exchange/user-id/events/holidays", false) - ExchangeEventsBasePath = mustAppendPath(ExchangeEventsRootPath, "holidays", false) - ExchangeEventsBasePath2 = mustAppendPath(ExchangeEventsRootPath, "moreholidays", false) - ExchangeEventsItemPath1 = mustAppendPath(ExchangeEventsBasePath, ItemName1, true) - ExchangeEventsItemPath2 = mustAppendPath(ExchangeEventsBasePath2, ItemName2, true) + ExchangeEventsRootPath = mustPathRep("tenant-id/exchange/user-id/events/holidays", false) + ExchangeEventsBasePath = ExchangeEventsRootPath.mustAppend("holidays", false) + ExchangeEventsBasePath2 = ExchangeEventsRootPath.mustAppend("moreholidays", false) + ExchangeEventsItemPath1 = ExchangeEventsBasePath.mustAppend(ItemName1, true) + ExchangeEventsItemPath2 = ExchangeEventsBasePath2.mustAppend(ItemName2, true) ExchangeEventsItems = []details.DetailsEntry{ { - RepoRef: ExchangeEventsItemPath1.String(), - ShortRef: ExchangeEventsItemPath1.ShortRef(), - ParentRef: ExchangeEventsItemPath1.ToBuilder().Dir().ShortRef(), - ItemRef: ExchangeEmailItemPath2.Item(), + RepoRef: ExchangeEventsItemPath1.RR.String(), + ShortRef: ExchangeEventsItemPath1.RR.ShortRef(), + ParentRef: ExchangeEventsItemPath1.RR.ToBuilder().Dir().ShortRef(), + ItemRef: ExchangeEventsItemPath1.ItemLocation(), + LocationRef: ExchangeEventsItemPath1.loc.String(), ItemInfo: details.ItemInfo{ Exchange: &details.ExchangeInfo{ ItemType: details.ExchangeEvent, @@ -156,10 +252,11 @@ var ( }, }, { - RepoRef: ExchangeEventsItemPath2.String(), - ShortRef: ExchangeEventsItemPath2.ShortRef(), - ParentRef: ExchangeEventsItemPath2.ToBuilder().Dir().ShortRef(), - ItemRef: ExchangeEmailItemPath2.Item(), + RepoRef: ExchangeEventsItemPath2.RR.String(), + ShortRef: ExchangeEventsItemPath2.RR.ShortRef(), + ParentRef: ExchangeEventsItemPath2.RR.ToBuilder().Dir().ShortRef(), + ItemRef: ExchangeEventsItemPath2.ItemLocation(), + LocationRef: ExchangeEventsItemPath2.loc.String(), ItemInfo: details.ItemInfo{ Exchange: &details.ExchangeInfo{ ItemType: details.ExchangeEvent, @@ -172,30 +269,31 @@ var ( }, } - OneDriveRootPath = mustParsePath("tenant-id/onedrive/user-id/files/drives/foo/root:", false) - OneDriveFolderPath = mustAppendPath(OneDriveRootPath, "folder", false) - OneDriveBasePath1 = mustAppendPath(OneDriveFolderPath, "a", false) - OneDriveBasePath2 = mustAppendPath(OneDriveFolderPath, "b", false) + OneDriveRootPath = mustPathRep("tenant-id/onedrive/user-id/files/drives/foo/root:", false) + OneDriveFolderPath = OneDriveRootPath.mustAppend("folder", false) + OneDriveBasePath1 = OneDriveFolderPath.mustAppend("a", false) + OneDriveBasePath2 = OneDriveFolderPath.mustAppend("b", false) - OneDriveItemPath1 = mustAppendPath(OneDriveFolderPath, ItemName1, true) - OneDriveItemPath2 = mustAppendPath(OneDriveBasePath1, ItemName2, true) - OneDriveItemPath3 = mustAppendPath(OneDriveBasePath2, ItemName3, true) + OneDriveItemPath1 = OneDriveFolderPath.mustAppend(ItemName1, true) + OneDriveItemPath2 = OneDriveBasePath1.mustAppend(ItemName2, true) + OneDriveItemPath3 = OneDriveBasePath2.mustAppend(ItemName3, true) - OneDriveFolderFolder = stdpath.Join(OneDriveFolderPath.Folders()[3:]...) - OneDriveParentFolder1 = stdpath.Join(OneDriveBasePath1.Folders()[3:]...) - OneDriveParentFolder2 = stdpath.Join(OneDriveBasePath2.Folders()[3:]...) + OneDriveFolderFolder = OneDriveFolderPath.loc.PopFront().String() + OneDriveParentFolder1 = OneDriveBasePath1.loc.PopFront().String() + OneDriveParentFolder2 = OneDriveBasePath2.loc.PopFront().String() OneDriveItems = []details.DetailsEntry{ { - RepoRef: OneDriveItemPath1.String(), - ShortRef: OneDriveItemPath1.ShortRef(), - ParentRef: OneDriveItemPath1.ToBuilder().Dir().ShortRef(), - ItemRef: OneDriveItemPath1.Item(), + RepoRef: OneDriveItemPath1.RR.String(), + ShortRef: OneDriveItemPath1.RR.ShortRef(), + ParentRef: OneDriveItemPath1.RR.ToBuilder().Dir().ShortRef(), + ItemRef: OneDriveItemPath1.ItemLocation(), + LocationRef: OneDriveItemPath1.loc.String(), ItemInfo: details.ItemInfo{ OneDrive: &details.OneDriveInfo{ ItemType: details.OneDriveItem, ParentPath: OneDriveFolderFolder, - ItemName: OneDriveItemPath1.Item() + "name", + ItemName: OneDriveItemPath1.ItemLocation() + "name", Size: int64(23), Owner: UserEmail1, Created: Time2, @@ -204,15 +302,16 @@ var ( }, }, { - RepoRef: OneDriveItemPath2.String(), - ShortRef: OneDriveItemPath2.ShortRef(), - ParentRef: OneDriveItemPath2.ToBuilder().Dir().ShortRef(), - ItemRef: OneDriveItemPath2.Item(), + RepoRef: OneDriveItemPath2.RR.String(), + ShortRef: OneDriveItemPath2.RR.ShortRef(), + ParentRef: OneDriveItemPath2.RR.ToBuilder().Dir().ShortRef(), + ItemRef: OneDriveItemPath2.ItemLocation(), + LocationRef: OneDriveItemPath2.loc.String(), ItemInfo: details.ItemInfo{ OneDrive: &details.OneDriveInfo{ ItemType: details.OneDriveItem, ParentPath: OneDriveParentFolder1, - ItemName: OneDriveItemPath2.Item() + "name", + ItemName: OneDriveItemPath2.ItemLocation() + "name", Size: int64(42), Owner: UserEmail1, Created: Time1, @@ -221,15 +320,16 @@ var ( }, }, { - RepoRef: OneDriveItemPath3.String(), - ShortRef: OneDriveItemPath3.ShortRef(), - ParentRef: OneDriveItemPath3.ToBuilder().Dir().ShortRef(), - ItemRef: OneDriveItemPath3.Item(), + RepoRef: OneDriveItemPath3.RR.String(), + ShortRef: OneDriveItemPath3.RR.ShortRef(), + ParentRef: OneDriveItemPath3.RR.ToBuilder().Dir().ShortRef(), + ItemRef: OneDriveItemPath3.ItemLocation(), + LocationRef: OneDriveItemPath3.loc.String(), ItemInfo: details.ItemInfo{ OneDrive: &details.OneDriveInfo{ ItemType: details.OneDriveItem, ParentPath: OneDriveParentFolder2, - ItemName: OneDriveItemPath3.Item() + "name", + ItemName: OneDriveItemPath3.ItemLocation() + "name", Size: int64(19), Owner: UserEmail2, Created: Time2, @@ -239,30 +339,31 @@ var ( }, } - SharePointRootPath = mustParsePath("tenant-id/sharepoint/site-id/libraries/drives/foo/root:", false) - SharePointLibraryPath = mustAppendPath(SharePointRootPath, "library", false) - SharePointBasePath1 = mustAppendPath(SharePointLibraryPath, "a", false) - SharePointBasePath2 = mustAppendPath(SharePointLibraryPath, "b", false) + SharePointRootPath = mustPathRep("tenant-id/sharepoint/site-id/libraries/drives/foo/root:", false) + SharePointLibraryPath = SharePointRootPath.mustAppend("library", false) + SharePointBasePath1 = SharePointLibraryPath.mustAppend("a", false) + SharePointBasePath2 = SharePointLibraryPath.mustAppend("b", false) - SharePointLibraryItemPath1 = mustAppendPath(SharePointLibraryPath, ItemName1, true) - SharePointLibraryItemPath2 = mustAppendPath(SharePointBasePath1, ItemName2, true) - SharePointLibraryItemPath3 = mustAppendPath(SharePointBasePath2, ItemName3, true) + SharePointLibraryItemPath1 = SharePointLibraryPath.mustAppend(ItemName1, true) + SharePointLibraryItemPath2 = SharePointBasePath1.mustAppend(ItemName2, true) + SharePointLibraryItemPath3 = SharePointBasePath2.mustAppend(ItemName3, true) - SharePointLibraryFolder = stdpath.Join(SharePointLibraryPath.Folders()[3:]...) - SharePointParentLibrary1 = stdpath.Join(SharePointBasePath1.Folders()[3:]...) - SharePointParentLibrary2 = stdpath.Join(SharePointBasePath2.Folders()[3:]...) + SharePointLibraryFolder = SharePointLibraryPath.loc.PopFront().String() + SharePointParentLibrary1 = SharePointBasePath1.loc.PopFront().String() + SharePointParentLibrary2 = SharePointBasePath2.loc.PopFront().String() SharePointLibraryItems = []details.DetailsEntry{ { - RepoRef: SharePointLibraryItemPath1.String(), - ShortRef: SharePointLibraryItemPath1.ShortRef(), - ParentRef: SharePointLibraryItemPath1.ToBuilder().Dir().ShortRef(), - ItemRef: SharePointLibraryItemPath1.Item(), + RepoRef: SharePointLibraryItemPath1.RR.String(), + ShortRef: SharePointLibraryItemPath1.RR.ShortRef(), + ParentRef: SharePointLibraryItemPath1.RR.ToBuilder().Dir().ShortRef(), + ItemRef: SharePointLibraryItemPath1.ItemLocation(), + LocationRef: SharePointLibraryItemPath1.loc.String(), ItemInfo: details.ItemInfo{ SharePoint: &details.SharePointInfo{ ItemType: details.SharePointLibrary, ParentPath: SharePointLibraryFolder, - ItemName: SharePointLibraryItemPath1.Item() + "name", + ItemName: SharePointLibraryItemPath1.ItemLocation() + "name", Size: int64(23), Owner: UserEmail1, Created: Time2, @@ -271,15 +372,16 @@ var ( }, }, { - RepoRef: SharePointLibraryItemPath2.String(), - ShortRef: SharePointLibraryItemPath2.ShortRef(), - ParentRef: SharePointLibraryItemPath2.ToBuilder().Dir().ShortRef(), - ItemRef: SharePointLibraryItemPath2.Item(), + RepoRef: SharePointLibraryItemPath2.RR.String(), + ShortRef: SharePointLibraryItemPath2.RR.ShortRef(), + ParentRef: SharePointLibraryItemPath2.RR.ToBuilder().Dir().ShortRef(), + ItemRef: SharePointLibraryItemPath2.ItemLocation(), + LocationRef: SharePointLibraryItemPath2.loc.String(), ItemInfo: details.ItemInfo{ SharePoint: &details.SharePointInfo{ ItemType: details.SharePointLibrary, ParentPath: SharePointParentLibrary1, - ItemName: SharePointLibraryItemPath2.Item() + "name", + ItemName: SharePointLibraryItemPath2.ItemLocation() + "name", Size: int64(42), Owner: UserEmail1, Created: Time1, @@ -288,15 +390,16 @@ var ( }, }, { - RepoRef: SharePointLibraryItemPath3.String(), - ShortRef: SharePointLibraryItemPath3.ShortRef(), - ParentRef: SharePointLibraryItemPath3.ToBuilder().Dir().ShortRef(), - ItemRef: SharePointLibraryItemPath3.Item(), + RepoRef: SharePointLibraryItemPath3.RR.String(), + ShortRef: SharePointLibraryItemPath3.RR.ShortRef(), + ParentRef: SharePointLibraryItemPath3.RR.ToBuilder().Dir().ShortRef(), + ItemRef: SharePointLibraryItemPath3.ItemLocation(), + LocationRef: SharePointLibraryItemPath3.loc.String(), ItemInfo: details.ItemInfo{ SharePoint: &details.SharePointInfo{ ItemType: details.SharePointLibrary, ParentPath: SharePointParentLibrary2, - ItemName: SharePointLibraryItemPath3.Item() + "name", + ItemName: SharePointLibraryItemPath3.ItemLocation() + "name", Size: int64(19), Owner: UserEmail2, Created: Time2, diff --git a/src/pkg/selectors/example_selectors_test.go b/src/pkg/selectors/example_selectors_test.go index 2e3260748..012a0b58b 100644 --- a/src/pkg/selectors/example_selectors_test.go +++ b/src/pkg/selectors/example_selectors_test.go @@ -123,9 +123,10 @@ var ( DetailsModel: details.DetailsModel{ Entries: []details.DetailsEntry{ { - RepoRef: "tID/exchange/your-user-id/email/example/itemID", - ShortRef: "xyz", - ItemRef: "123", + RepoRef: "tID/exchange/your-user-id/email/example/itemID", + LocationRef: "example", + ShortRef: "xyz", + ItemRef: "123", ItemInfo: details.ItemInfo{ Exchange: &details.ExchangeInfo{ ItemType: details.ExchangeMail, diff --git a/src/pkg/selectors/exchange.go b/src/pkg/selectors/exchange.go index ccee7f948..4b0ac0ae5 100644 --- a/src/pkg/selectors/exchange.go +++ b/src/pkg/selectors/exchange.go @@ -618,14 +618,10 @@ func (ec exchangeCategory) pathValues( } result := map[categorizer][]string{ - folderCat: {repo.Folder(false)}, + folderCat: {ent.LocationRef}, itemCat: {item, ent.ShortRef}, } - if len(ent.LocationRef) > 0 { - result[folderCat] = append(result[folderCat], ent.LocationRef) - } - return result, nil } diff --git a/src/pkg/selectors/exchange_test.go b/src/pkg/selectors/exchange_test.go index 703ea6f72..5218c153b 100644 --- a/src/pkg/selectors/exchange_test.go +++ b/src/pkg/selectors/exchange_test.go @@ -713,9 +713,9 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesInfo() { func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesPath() { const ( usr = "userID" - fID1 = "mf_id_1" + fID1 = "mf_id_1.d" fld1 = "mailFolder" - fID2 = "mf_id_2" + fID2 = "mf_id_2.d" fld2 = "subFolder" mail = "mailID" ) @@ -743,18 +743,18 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesPath() { {"all folders", es.MailFolders(Any()), "", assert.True}, {"no folders", es.MailFolders(None()), "", assert.False}, {"matching folder", es.MailFolders([]string{fld1}), "", assert.True}, - {"matching folder id", es.MailFolders([]string{fID1}), "", assert.True}, + {"matching folder id", es.MailFolders([]string{fID1}), "", assert.False}, {"incomplete matching folder", es.MailFolders([]string{"mail"}), "", assert.False}, {"incomplete matching folder ID", es.MailFolders([]string{"mf_id"}), "", assert.False}, {"non-matching folder", es.MailFolders([]string{"smarf"}), "", assert.False}, {"non-matching folder substring", es.MailFolders([]string{fld1 + "_suffix"}), "", assert.False}, {"non-matching folder id substring", es.MailFolders([]string{fID1 + "_suffix"}), "", assert.False}, {"matching folder prefix", es.MailFolders([]string{fld1}, PrefixMatch()), "", assert.True}, - {"matching folder ID prefix", es.MailFolders([]string{fID1}, PrefixMatch()), "", assert.True}, + {"matching folder ID prefix", es.MailFolders([]string{fID1}, PrefixMatch()), "", assert.False}, {"incomplete folder prefix", es.MailFolders([]string{"mail"}, PrefixMatch()), "", assert.False}, {"matching folder substring", es.MailFolders([]string{"Folder"}), "", assert.False}, {"one of multiple folders", es.MailFolders([]string{"smarf", fld2}), "", assert.True}, - {"one of multiple folders by ID", es.MailFolders([]string{"smarf", fID2}), "", assert.True}, + {"one of multiple folders by ID", es.MailFolders([]string{"smarf", fID2}), "", assert.False}, {"all mail", es.Mails(Any(), Any()), "", assert.True}, {"no mail", es.Mails(Any(), None()), "", assert.False}, {"matching mail", es.Mails(Any(), []string{mail}), "", assert.True}, @@ -777,10 +777,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesPath() { aMatch = true break } - if matchesPathValues(scope, ExchangeMail, pvs) { - aMatch = true - break - } } test.expect(t, aMatch) }) @@ -789,13 +785,41 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesPath() { func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { var ( - contact = stubRepoRef(path.ExchangeService, path.ContactsCategory, "uid", "cfld", "cid") - event = stubRepoRef(path.ExchangeService, path.EventsCategory, "uid", "ecld", "eid") - mail = stubRepoRef(path.ExchangeService, path.EmailCategory, "uid", "mfld", "mid") - contactInSubFolder = stubRepoRef(path.ExchangeService, path.ContactsCategory, "uid", "cfld1/cfld2", "cid") + contact = stubPath( + suite.T(), + "uid", + []string{"cfld", "cid"}, + path.ContactsCategory) + event = stubPath( + suite.T(), + "uid", + []string{"efld", "eid"}, + path.EventsCategory) + mail = stubPath( + suite.T(), + "uid", + []string{"mfld", "mid"}, + path.EmailCategory) + contactInSubFolder = stubPath( + suite.T(), + "uid", + []string{"cfld1/cfld2", "cid"}, + path.ContactsCategory) ) - makeDeets := func(refs ...string) *details.Details { + toRR := func(p path.Path) string { + newElems := []string{} + + for _, e := range p.Folders() { + newElems = append(newElems, e+".d") + } + + joinedFldrs := strings.Join(newElems, "/") + + return stubRepoRef(p.Service(), p.Category(), p.ResourceOwner(), joinedFldrs, p.Item()) + } + + makeDeets := func(refs ...path.Path) *details.Details { deets := &details.Details{ DetailsModel: details.DetailsModel{ Entries: []details.DetailsEntry{}, @@ -815,7 +839,9 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { } deets.Entries = append(deets.Entries, details.DetailsEntry{ - RepoRef: r, + RepoRef: toRR(r), + // Don't escape because we assume nice paths. + LocationRef: r.Folder(false), ItemInfo: details.ItemInfo{ Exchange: &details.ExchangeInfo{ ItemType: itype, @@ -851,7 +877,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Include(er.AllData()) return er }, - []string{contact}, + []string{toRR(contact)}, }, { "event only", @@ -861,7 +887,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Include(er.AllData()) return er }, - []string{event}, + []string{toRR(event)}, }, { "mail only", @@ -871,7 +897,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Include(er.AllData()) return er }, - []string{mail}, + []string{toRR(mail)}, }, { "all", @@ -881,7 +907,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Include(er.AllData()) return er }, - []string{contact, event, mail}, + []string{toRR(contact), toRR(event), toRR(mail)}, }, { "only match contact", @@ -891,7 +917,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Include(er.Contacts([]string{"cfld"}, []string{"cid"})) return er }, - []string{contact}, + []string{toRR(contact)}, }, { "only match contactInSubFolder", @@ -901,7 +927,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Include(er.ContactFolders([]string{"cfld1/cfld2"})) return er }, - []string{contactInSubFolder}, + []string{toRR(contactInSubFolder)}, }, { "only match contactInSubFolder by prefix", @@ -911,7 +937,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Include(er.ContactFolders([]string{"cfld1/cfld2"}, PrefixMatch())) return er }, - []string{contactInSubFolder}, + []string{toRR(contactInSubFolder)}, }, { "only match contactInSubFolder by leaf folder", @@ -921,17 +947,17 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Include(er.ContactFolders([]string{"cfld2"})) return er }, - []string{contactInSubFolder}, + []string{toRR(contactInSubFolder)}, }, { "only match event", makeDeets(contact, event, mail), func() *ExchangeRestore { er := NewExchangeRestore([]string{"uid"}) - er.Include(er.Events([]string{"ecld"}, []string{"eid"})) + er.Include(er.Events([]string{"efld"}, []string{"eid"})) return er }, - []string{event}, + []string{toRR(event)}, }, { "only match mail", @@ -941,7 +967,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Include(er.Mails([]string{"mfld"}, []string{"mid"})) return er }, - []string{mail}, + []string{toRR(mail)}, }, { "exclude contact", @@ -952,7 +978,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Exclude(er.Contacts([]string{"cfld"}, []string{"cid"})) return er }, - []string{event, mail}, + []string{toRR(event), toRR(mail)}, }, { "exclude event", @@ -960,10 +986,10 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { func() *ExchangeRestore { er := NewExchangeRestore(Any()) er.Include(er.AllData()) - er.Exclude(er.Events([]string{"ecld"}, []string{"eid"})) + er.Exclude(er.Events([]string{"efld"}, []string{"eid"})) return er }, - []string{contact, mail}, + []string{toRR(contact), toRR(mail)}, }, { "exclude mail", @@ -974,7 +1000,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Exclude(er.Mails([]string{"mfld"}, []string{"mid"})) return er }, - []string{contact, event}, + []string{toRR(contact), toRR(event)}, }, { "filter on mail subject", @@ -991,7 +1017,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Filter(er.MailSubject("subj")) return er }, - []string{mail}, + []string{toRR(mail)}, }, { "filter on mail subject multiple input categories", @@ -1012,7 +1038,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { er.Filter(er.MailSubject("subj")) return er }, - []string{mail}, + []string{toRR(mail)}, }, } for _, test := range table { @@ -1466,38 +1492,43 @@ func (suite *ExchangeSelectorSuite) TestExchangeCategory_leafCat() { func (suite *ExchangeSelectorSuite) TestExchangeCategory_PathValues() { t := suite.T() - contactPath := stubPath(t, "user", []string{"cfolder", "contactitem"}, path.ContactsCategory) + contactPath := stubPath(t, "user", []string{"cfolder.d", "contactitem.d"}, path.ContactsCategory) + contactLoc := stubPath(t, "user", []string{"cfolder", "contactitem"}, path.ContactsCategory) contactMap := map[categorizer][]string{ - ExchangeContactFolder: {contactPath.Folder(false)}, + ExchangeContactFolder: {contactLoc.Folder(false)}, ExchangeContact: {contactPath.Item(), "short"}, } - eventPath := stubPath(t, "user", []string{"ecalendar", "eventitem"}, path.EventsCategory) + eventPath := stubPath(t, "user", []string{"ecalendar.d", "eventitem.d"}, path.EventsCategory) + eventLoc := stubPath(t, "user", []string{"ecalendar", "eventitem"}, path.EventsCategory) eventMap := map[categorizer][]string{ - ExchangeEventCalendar: {eventPath.Folder(false)}, + ExchangeEventCalendar: {eventLoc.Folder(false)}, ExchangeEvent: {eventPath.Item(), "short"}, } - mailPath := stubPath(t, "user", []string{"mfolder", "mailitem"}, path.EmailCategory) + mailPath := stubPath(t, "user", []string{"mfolder.d", "mailitem.d"}, path.EmailCategory) + mailLoc := stubPath(t, "user", []string{"mfolder", "mailitem"}, path.EmailCategory) mailMap := map[categorizer][]string{ - ExchangeMailFolder: {mailPath.Folder(false)}, + ExchangeMailFolder: {mailLoc.Folder(false)}, ExchangeMail: {mailPath.Item(), "short"}, } table := []struct { cat exchangeCategory path path.Path + loc path.Path expect map[categorizer][]string }{ - {ExchangeContact, contactPath, contactMap}, - {ExchangeEvent, eventPath, eventMap}, - {ExchangeMail, mailPath, mailMap}, + {ExchangeContact, contactPath, contactLoc, contactMap}, + {ExchangeEvent, eventPath, eventLoc, eventMap}, + {ExchangeMail, mailPath, mailLoc, mailMap}, } for _, test := range table { suite.Run(string(test.cat), func() { t := suite.T() ent := details.DetailsEntry{ - RepoRef: test.path.String(), - ShortRef: "short", - ItemRef: test.path.Item(), + RepoRef: test.path.String(), + ShortRef: "short", + LocationRef: test.loc.Folder(true), + ItemRef: test.path.Item(), } pvs, err := test.cat.pathValues(test.path, ent, Config{}) diff --git a/src/pkg/selectors/onedrive.go b/src/pkg/selectors/onedrive.go index bd1837feb..9172d184f 100644 --- a/src/pkg/selectors/onedrive.go +++ b/src/pkg/selectors/onedrive.go @@ -399,7 +399,7 @@ func (c oneDriveCategory) pathValues( } // Ignore `drives//root:` for folder comparison - rFld := path.Builder{}.Append(repo.Folders()...).PopFront().PopFront().PopFront().String() + rFld := ent.OneDrive.ParentPath item := ent.ItemRef if len(item) == 0 { diff --git a/src/pkg/selectors/onedrive_test.go b/src/pkg/selectors/onedrive_test.go index 3bf953bf9..6eda3ef26 100644 --- a/src/pkg/selectors/onedrive_test.go +++ b/src/pkg/selectors/onedrive_test.go @@ -163,9 +163,27 @@ func (suite *OneDriveSelectorSuite) TestToOneDriveRestore() { func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { var ( - 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") + 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{ @@ -176,8 +194,9 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { ItemRef: "file", ItemInfo: details.ItemInfo{ OneDrive: &details.OneDriveInfo{ - ItemType: details.OneDriveItem, - ItemName: "fileName", + ItemType: details.OneDriveItem, + ItemName: "fileName", + ParentPath: fileParent, }, }, }, @@ -186,8 +205,9 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { ItemRef: "file2", ItemInfo: details.ItemInfo{ OneDrive: &details.OneDriveInfo{ - ItemType: details.OneDriveItem, - ItemName: "fileName2", + ItemType: details.OneDriveItem, + ItemName: "fileName2", + ParentPath: fileParent2, }, }, }, @@ -196,8 +216,9 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { // item ref intentionally blank to assert fallback case ItemInfo: details.ItemInfo{ OneDrive: &details.OneDriveInfo{ - ItemType: details.OneDriveItem, - ItemName: "fileName3", + ItemType: details.OneDriveItem, + ItemName: "fileName3", + ParentPath: fileParent3, }, }, }, @@ -211,14 +232,12 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { table := []struct { name string - deets *details.Details makeSelector func() *OneDriveRestore expect []string cfg Config }{ { - name: "all", - deets: deets, + name: "all", makeSelector: func() *OneDriveRestore { odr := NewOneDriveRestore(Any()) odr.Include(odr.AllData()) @@ -227,8 +246,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { expect: arr(file, file2, file3), }, { - name: "only match file", - deets: deets, + name: "only match file", makeSelector: func() *OneDriveRestore { odr := NewOneDriveRestore(Any()) odr.Include(odr.Items(Any(), []string{"file2"})) @@ -237,8 +255,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { expect: arr(file2), }, { - name: "id doesn't match name", - deets: deets, + name: "id doesn't match name", makeSelector: func() *OneDriveRestore { odr := NewOneDriveRestore(Any()) odr.Include(odr.Items(Any(), []string{"file2"})) @@ -248,8 +265,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { cfg: Config{OnlyMatchItemNames: true}, }, { - name: "only match file name", - deets: deets, + name: "only match file name", makeSelector: func() *OneDriveRestore { odr := NewOneDriveRestore(Any()) odr.Include(odr.Items(Any(), []string{"fileName2"})) @@ -259,8 +275,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { cfg: Config{OnlyMatchItemNames: true}, }, { - name: "name doesn't match id", - deets: deets, + name: "name doesn't match id", makeSelector: func() *OneDriveRestore { odr := NewOneDriveRestore(Any()) odr.Include(odr.Items(Any(), []string{"fileName2"})) @@ -269,8 +284,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { expect: []string{}, }, { - name: "only match folder", - deets: deets, + name: "only match folder", makeSelector: func() *OneDriveRestore { odr := NewOneDriveRestore([]string{"uid"}) odr.Include(odr.Folders([]string{"folderA/folderB", "folderA/folderC"})) @@ -288,7 +302,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() { sel := test.makeSelector() sel.Configure(test.cfg) - results := sel.Reduce(ctx, test.deets, fault.New(true)) + results := sel.Reduce(ctx, deets, fault.New(true)) paths := results.Paths() assert.Equal(t, test.expect, paths) }) @@ -301,11 +315,13 @@ func (suite *OneDriveSelectorSuite) TestOneDriveCategory_PathValues() { fileName := "file" fileID := fileName + "-id" shortRef := "short" - elems := []string{"drive", "driveID", "root:", "dir1", "dir2", fileID} + 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 @@ -351,7 +367,8 @@ func (suite *OneDriveSelectorSuite) TestOneDriveCategory_PathValues() { ItemRef: fileID, ItemInfo: details.ItemInfo{ OneDrive: &details.OneDriveInfo{ - ItemName: fileName, + ItemName: fileName, + ParentPath: fileLoc.String(), }, }, } diff --git a/src/pkg/selectors/selectors_reduce_test.go b/src/pkg/selectors/selectors_reduce_test.go index 6229dc164..dcb0a9855 100644 --- a/src/pkg/selectors/selectors_reduce_test.go +++ b/src/pkg/selectors/selectors_reduce_test.go @@ -48,7 +48,7 @@ func (suite *SelectorReduceSuite) TestReduce() { selFunc: func() selectors.Reducer { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.MailFolders( - []string{testdata.ExchangeEmailInboxPath.Folder(false)}, + []string{testdata.ExchangeEmailInboxPath.FolderLocation()}, )) return sel @@ -72,7 +72,7 @@ func (suite *SelectorReduceSuite) TestReduce() { sel.Filter(sel.MailSender("a-person")) sel.Exclude(sel.Mails( selectors.Any(), - []string{testdata.ExchangeEmailItemPath2.ShortRef()}, + []string{testdata.ExchangeEmailItemPath2.RR.ShortRef()}, )) return sel @@ -110,7 +110,7 @@ func (suite *SelectorReduceSuite) TestReduce() { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.Mails( selectors.Any(), - []string{testdata.ExchangeEmailItemPath1.Item()}, + []string{testdata.ExchangeEmailItemPath1.ItemLocation()}, )) return sel @@ -123,7 +123,7 @@ func (suite *SelectorReduceSuite) TestReduce() { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.Mails( selectors.Any(), - []string{testdata.ExchangeEmailItemPath1.ShortRef()}, + []string{testdata.ExchangeEmailItemPath1.RR.ShortRef()}, )) return sel @@ -177,7 +177,7 @@ func (suite *SelectorReduceSuite) TestReduce() { selFunc: func() selectors.Reducer { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.MailFolders( - []string{testdata.ExchangeEmailBasePath.Folder(false)}, + []string{testdata.ExchangeEmailBasePath.FolderLocation()}, )) return sel @@ -192,7 +192,7 @@ func (suite *SelectorReduceSuite) TestReduce() { selFunc: func() selectors.Reducer { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.MailFolders( - []string{testdata.ExchangeEmailBasePath.Folder(false)}, + []string{testdata.ExchangeEmailBasePath.FolderLocation()}, selectors.PrefixMatch(), // force prefix matching )) @@ -205,7 +205,7 @@ func (suite *SelectorReduceSuite) TestReduce() { selFunc: func() selectors.Reducer { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.MailFolders( - []string{testdata.ExchangeEmailInboxPath.Folder(false)}, + []string{testdata.ExchangeEmailInboxPath.FolderLocation()}, )) return sel @@ -217,7 +217,7 @@ func (suite *SelectorReduceSuite) TestReduce() { selFunc: func() selectors.Reducer { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.ContactFolders( - []string{testdata.ExchangeContactsBasePath.Folder(false)}, + []string{testdata.ExchangeContactsBasePath.FolderLocation()}, )) return sel @@ -229,7 +229,7 @@ func (suite *SelectorReduceSuite) TestReduce() { selFunc: func() selectors.Reducer { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.ContactFolders( - []string{testdata.ExchangeContactsRootPath.Folder(false)}, + []string{testdata.ExchangeContactsRootPath.FolderLocation()}, )) return sel @@ -242,7 +242,7 @@ func (suite *SelectorReduceSuite) TestReduce() { selFunc: func() selectors.Reducer { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.EventCalendars( - []string{testdata.ExchangeEventsBasePath.Folder(false)}, + []string{testdata.ExchangeEventsBasePath.FolderLocation()}, )) return sel @@ -254,7 +254,7 @@ func (suite *SelectorReduceSuite) TestReduce() { selFunc: func() selectors.Reducer { sel := selectors.NewExchangeRestore(selectors.Any()) sel.Include(sel.EventCalendars( - []string{testdata.ExchangeEventsRootPath.Folder(false)}, + []string{testdata.ExchangeEventsRootPath.FolderLocation()}, )) return sel diff --git a/src/pkg/selectors/sharepoint.go b/src/pkg/selectors/sharepoint.go index defa6d206..eccc4e18e 100644 --- a/src/pkg/selectors/sharepoint.go +++ b/src/pkg/selectors/sharepoint.go @@ -520,9 +520,9 @@ func (c sharePointCategory) pathValues( cfg Config, ) (map[categorizer][]string, error) { var ( - folderCat, itemCat categorizer - dropDriveFolderPrefix bool - itemID string + folderCat, itemCat categorizer + itemID string + rFld string ) switch c { @@ -531,25 +531,21 @@ func (c sharePointCategory) pathValues( return nil, clues.New("no SharePoint ItemInfo in details") } - dropDriveFolderPrefix = true folderCat, itemCat = SharePointLibraryFolder, SharePointLibraryItem + rFld = ent.SharePoint.ParentPath case SharePointList, SharePointListItem: folderCat, itemCat = SharePointList, SharePointListItem + rFld = ent.LocationRef case SharePointPage, SharePointPageFolder: folderCat, itemCat = SharePointPageFolder, SharePointPage + rFld = ent.LocationRef default: return nil, clues.New("unrecognized sharePointCategory").With("category", c) } - rFld := repo.Folder(false) - if dropDriveFolderPrefix { - // like onedrive, ignore `drives//root:` for library folder comparison - rFld = path.Builder{}.Append(repo.Folders()...).PopFront().PopFront().PopFront().String() - } - item := ent.ItemRef if len(item) == 0 { item = repo.Item() @@ -568,10 +564,6 @@ func (c sharePointCategory) pathValues( result[itemCat] = append(result[itemCat], itemID) } - if len(ent.LocationRef) > 0 { - result[folderCat] = append(result[folderCat], ent.LocationRef) - } - return result, nil } diff --git a/src/pkg/selectors/sharepoint_test.go b/src/pkg/selectors/sharepoint_test.go index e606ff5e2..a8250a04e 100644 --- a/src/pkg/selectors/sharepoint_test.go +++ b/src/pkg/selectors/sharepoint_test.go @@ -1,6 +1,7 @@ package selectors import ( + "strings" "testing" "time" @@ -8,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "golang.org/x/exp/slices" "github.com/alcionai/corso/src/internal/common" "github.com/alcionai/corso/src/internal/tester" @@ -204,67 +206,111 @@ func (suite *SharePointSelectorSuite) TestToSharePointRestore() { } func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { + toRR := func(cat path.CategoryType, siteID string, folders []string, item string) string { + folderElems := make([]string, 0, len(folders)) + + for _, f := range folders { + folderElems = append(folderElems, f+".d") + } + + return stubRepoRef( + path.SharePointService, + cat, + siteID, + strings.Join(folderElems, "/"), + item) + } + var ( - drivePfx = "drive/drive!id/root:/" - pairAC = "folderA/folderC" - pairGH = "folderG/folderH" - item = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", drivePfx+"folderA/folderB", "item") - item2 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", drivePfx+pairAC, "item2") - item3 = stubRepoRef(path.SharePointService, path.LibrariesCategory, "sid", drivePfx+"folderD/folderE", "item3") - item4 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item4") - item5 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item5") + prefixElems = []string{ + "drive", + "drive!id", + "root:", + } + itemElems1 = []string{"folderA", "folderB"} + itemElems2 = []string{"folderA", "folderC"} + itemElems3 = []string{"folderD", "folderE"} + pairAC = "folderA/folderC" + pairGH = "folderG/folderH" + item = toRR( + path.LibrariesCategory, + "sid", + append(slices.Clone(prefixElems), itemElems1...), + "item") + item2 = toRR( + path.LibrariesCategory, + "sid", + append(slices.Clone(prefixElems), itemElems2...), + "item2") + item3 = toRR( + path.LibrariesCategory, + "sid", + append(slices.Clone(prefixElems), itemElems3...), + "item3") + item4 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item4") + item5 = stubRepoRef(path.SharePointService, path.PagesCategory, "sid", pairGH, "item5") ) deets := &details.Details{ DetailsModel: details.DetailsModel{ Entries: []details.DetailsEntry{ { - RepoRef: item, - ItemRef: "item", + RepoRef: item, + ItemRef: "item", + LocationRef: strings.Join(append([]string{"root:"}, itemElems1...), "/"), ItemInfo: details.ItemInfo{ SharePoint: &details.SharePointInfo{ - ItemType: details.SharePointLibrary, - ItemName: "itemName", + ItemType: details.SharePointLibrary, + ItemName: "itemName", + ParentPath: strings.Join(itemElems1, "/"), }, }, }, { - RepoRef: item2, + RepoRef: item2, + LocationRef: strings.Join(append([]string{"root:"}, itemElems2...), "/"), // ItemRef intentionally blank to test fallback case ItemInfo: details.ItemInfo{ SharePoint: &details.SharePointInfo{ - ItemType: details.SharePointLibrary, - ItemName: "itemName2", + ItemType: details.SharePointLibrary, + ItemName: "itemName2", + ParentPath: strings.Join(itemElems2, "/"), }, }, }, { - RepoRef: item3, - ItemRef: "item3", + RepoRef: item3, + ItemRef: "item3", + LocationRef: strings.Join(append([]string{"root:"}, itemElems3...), "/"), ItemInfo: details.ItemInfo{ SharePoint: &details.SharePointInfo{ - ItemType: details.SharePointLibrary, - ItemName: "itemName3", + ItemType: details.SharePointLibrary, + ItemName: "itemName3", + ParentPath: strings.Join(itemElems3, "/"), }, }, }, { - RepoRef: item4, - ItemRef: "item4", + RepoRef: item4, + LocationRef: pairGH, + ItemRef: "item4", ItemInfo: details.ItemInfo{ SharePoint: &details.SharePointInfo{ - ItemType: details.SharePointPage, - ItemName: "itemName4", + ItemType: details.SharePointPage, + ItemName: "itemName4", + ParentPath: pairGH, }, }, }, { - RepoRef: item5, + RepoRef: item5, + LocationRef: pairGH, // ItemRef intentionally blank to test fallback case ItemInfo: details.ItemInfo{ SharePoint: &details.SharePointInfo{ - ItemType: details.SharePointPage, - ItemName: "itemName5", + ItemType: details.SharePointPage, + ItemName: "itemName5", + ParentPath: pairGH, }, }, }, @@ -278,14 +324,12 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { table := []struct { name string - deets *details.Details makeSelector func() *SharePointRestore expect []string cfg Config }{ { - name: "all", - deets: deets, + name: "all", makeSelector: func() *SharePointRestore { odr := NewSharePointRestore(Any()) odr.Include(odr.AllData()) @@ -294,8 +338,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { expect: arr(item, item2, item3, item4, item5), }, { - name: "only match item", - deets: deets, + name: "only match item", makeSelector: func() *SharePointRestore { odr := NewSharePointRestore(Any()) odr.Include(odr.LibraryItems(Any(), []string{"item2"})) @@ -304,8 +347,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { expect: arr(item2), }, { - name: "id doesn't match name", - deets: deets, + name: "id doesn't match name", makeSelector: func() *SharePointRestore { odr := NewSharePointRestore(Any()) odr.Include(odr.LibraryItems(Any(), []string{"item2"})) @@ -315,8 +357,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { cfg: Config{OnlyMatchItemNames: true}, }, { - name: "only match item name", - deets: deets, + name: "only match item name", makeSelector: func() *SharePointRestore { odr := NewSharePointRestore(Any()) odr.Include(odr.LibraryItems(Any(), []string{"itemName2"})) @@ -326,8 +367,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { cfg: Config{OnlyMatchItemNames: true}, }, { - name: "name doesn't match", - deets: deets, + name: "name doesn't match", makeSelector: func() *SharePointRestore { odr := NewSharePointRestore(Any()) odr.Include(odr.LibraryItems(Any(), []string{"itemName2"})) @@ -336,8 +376,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { expect: []string{}, }, { - name: "only match folder", - deets: deets, + name: "only match folder", makeSelector: func() *SharePointRestore { odr := NewSharePointRestore([]string{"sid"}) odr.Include(odr.LibraryFolders([]string{"folderA/folderB", pairAC})) @@ -346,8 +385,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { expect: arr(item, item2), }, { - name: "pages match folder", - deets: deets, + name: "pages match folder", makeSelector: func() *SharePointRestore { odr := NewSharePointRestore([]string{"sid"}) odr.Include(odr.Pages([]string{pairGH, pairAC})) @@ -365,7 +403,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() { sel := test.makeSelector() sel.Configure(test.cfg) - results := sel.Reduce(ctx, test.deets, fault.New(true)) + results := sel.Reduce(ctx, deets, fault.New(true)) paths := results.Paths() assert.Equal(t, test.expect, paths) }) @@ -377,21 +415,25 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() { itemName = "item" itemID = "item-id" shortRef = "short" - driveElems = []string{"drive", "drive!id", "root:", "dir1", "dir2", itemID} + driveElems = []string{"drive", "drive!id", "root:.d", "dir1.d", "dir2.d", itemID} elems = []string{"dir1", "dir2", itemID} ) table := []struct { - name string - sc sharePointCategory - pathElems []string - expected map[categorizer][]string - cfg Config + name string + sc sharePointCategory + pathElems []string + locRef string + parentPath string + expected map[categorizer][]string + cfg Config }{ { - name: "SharePoint Libraries", - sc: SharePointLibraryItem, - pathElems: driveElems, + name: "SharePoint Libraries", + sc: SharePointLibraryItem, + pathElems: driveElems, + locRef: "root:/dir1/dir2", + parentPath: "dir1/dir2", expected: map[categorizer][]string{ SharePointLibraryFolder: {"dir1/dir2"}, SharePointLibraryItem: {itemID, shortRef}, @@ -399,9 +441,11 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() { cfg: Config{}, }, { - name: "SharePoint Libraries w/ name", - sc: SharePointLibraryItem, - pathElems: driveElems, + name: "SharePoint Libraries w/ name", + sc: SharePointLibraryItem, + pathElems: driveElems, + locRef: "root:/dir1/dir2", + parentPath: "dir1/dir2", expected: map[categorizer][]string{ SharePointLibraryFolder: {"dir1/dir2"}, SharePointLibraryItem: {itemName, shortRef}, @@ -412,6 +456,7 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() { name: "SharePoint Lists", sc: SharePointListItem, pathElems: elems, + locRef: "dir1/dir2", expected: map[categorizer][]string{ SharePointList: {"dir1/dir2"}, SharePointListItem: {itemID, shortRef}, @@ -434,12 +479,14 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() { require.NoError(t, err, clues.ToCore(err)) ent := details.DetailsEntry{ - RepoRef: itemPath.String(), - ShortRef: shortRef, - ItemRef: itemPath.Item(), + RepoRef: itemPath.String(), + ShortRef: shortRef, + ItemRef: itemPath.Item(), + LocationRef: test.locRef, ItemInfo: details.ItemInfo{ SharePoint: &details.SharePointInfo{ - ItemName: itemName, + ItemName: itemName, + ParentPath: test.parentPath, }, }, }