SharePoint List selector Expansion (#1786)
## Description Initial changes to support SharePoint Lists being chosen for Backup Operations. <!-- Insert PR description--> ## Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🌻 Feature ## Issue(s) * close #1785<issue> ## Test Plan - [x] ⚡ Unit test
This commit is contained in:
parent
ea445ec471
commit
0d5043aa1f
@ -41,7 +41,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: empty,
|
||||
WebURLs: empty,
|
||||
},
|
||||
expectIncludeLen: 1,
|
||||
expectIncludeLen: 2,
|
||||
},
|
||||
{
|
||||
name: "single inputs",
|
||||
@ -51,7 +51,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: single,
|
||||
WebURLs: single,
|
||||
},
|
||||
expectIncludeLen: 2,
|
||||
expectIncludeLen: 3,
|
||||
},
|
||||
{
|
||||
name: "multi inputs",
|
||||
@ -61,7 +61,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: multi,
|
||||
WebURLs: multi,
|
||||
},
|
||||
expectIncludeLen: 2,
|
||||
expectIncludeLen: 3,
|
||||
},
|
||||
{
|
||||
name: "library contains",
|
||||
@ -101,7 +101,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: empty,
|
||||
WebURLs: containsOnly,
|
||||
},
|
||||
expectIncludeLen: 1,
|
||||
expectIncludeLen: 2,
|
||||
},
|
||||
{
|
||||
name: "library suffixes",
|
||||
@ -111,7 +111,7 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: empty,
|
||||
WebURLs: prefixOnly, // prefix pattern matches suffix pattern
|
||||
},
|
||||
expectIncludeLen: 1,
|
||||
expectIncludeLen: 2,
|
||||
},
|
||||
{
|
||||
name: "library suffixes and contains",
|
||||
@ -121,15 +121,16 @@ func (suite *SharePointUtilsSuite) TestIncludeSharePointRestoreDataSelectors() {
|
||||
Sites: empty,
|
||||
WebURLs: containsAndPrefix, // prefix pattern matches suffix pattern
|
||||
},
|
||||
expectIncludeLen: 2,
|
||||
expectIncludeLen: 4,
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
sel := selectors.NewSharePointRestore()
|
||||
// no return, mutates sel as a side effect
|
||||
t.Logf("Options sent: %v\n", test.opts)
|
||||
utils.IncludeSharePointRestoreDataSelectors(sel, test.opts)
|
||||
assert.Len(t, sel.Includes, test.expectIncludeLen)
|
||||
assert.Len(t, sel.Includes, test.expectIncludeLen, sel)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ func SendMailToBackStore(
|
||||
sentMessage, err := service.Client().UsersById(user).MailFoldersById(destination).Messages().Post(ctx, message, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err,
|
||||
user+": failure sendMailAPI: "+support.ConnectorStackErrorTrace(err),
|
||||
user+": failure sendMailAPI: Dest: "+destination+" Details: "+support.ConnectorStackErrorTrace(err),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -509,8 +509,8 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_sharePoint() {
|
||||
siteID = tester.M365SiteID(t)
|
||||
sel = selectors.NewSharePointBackup()
|
||||
)
|
||||
|
||||
sel.Include(sel.Sites([]string{siteID}))
|
||||
// TODO: dadams39 Issue #1795: Revert to Sites Upon List Integration
|
||||
sel.Include(sel.Libraries([]string{siteID}, selectors.Any()))
|
||||
|
||||
bo, _, _, _, closer := prepNewBackupOp(t, ctx, mb, sel.Selector)
|
||||
defer closer()
|
||||
|
||||
@ -190,14 +190,23 @@ func (s *sharePoint) DiscreteScopes(siteIDs []string) []SharePointScope {
|
||||
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
|
||||
// If any slice is empty, it defaults to [selectors.None]
|
||||
func (s *SharePointRestore) WebURL(urlSuffixes []string, opts ...option) []SharePointScope {
|
||||
return []SharePointScope{
|
||||
scopes := []SharePointScope{}
|
||||
|
||||
scopes = append(
|
||||
scopes,
|
||||
makeFilterScope[SharePointScope](
|
||||
SharePointLibraryItem,
|
||||
SharePointWebURL,
|
||||
urlSuffixes,
|
||||
pathFilterFactory(opts...)),
|
||||
// TODO: list scope
|
||||
}
|
||||
makeFilterScope[SharePointScope](
|
||||
SharePointListItem,
|
||||
SharePointWebURL,
|
||||
urlSuffixes,
|
||||
pathFilterFactory(opts...)),
|
||||
)
|
||||
|
||||
return scopes
|
||||
}
|
||||
|
||||
// Produces one or more SharePoint site scopes.
|
||||
@ -208,7 +217,43 @@ func (s *SharePointRestore) WebURL(urlSuffixes []string, opts ...option) []Share
|
||||
func (s *sharePoint) Sites(sites []string) []SharePointScope {
|
||||
scopes := []SharePointScope{}
|
||||
|
||||
scopes = append(scopes, makeScope[SharePointScope](SharePointLibrary, sites, Any()))
|
||||
scopes = append(
|
||||
scopes,
|
||||
makeScope[SharePointScope](SharePointLibrary, sites, Any()),
|
||||
makeScope[SharePointScope](SharePointList, sites, Any()),
|
||||
)
|
||||
|
||||
return scopes
|
||||
}
|
||||
|
||||
// Lists produces one or more SharePoint list scopes.
|
||||
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
|
||||
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
|
||||
// Any empty slice defaults to [selectors.None]
|
||||
func (s *sharePoint) Lists(sites, lists []string, opts ...option) []SharePointScope {
|
||||
var (
|
||||
scopes = []SharePointScope{}
|
||||
os = append([]option{pathComparator()}, opts...)
|
||||
)
|
||||
|
||||
scopes = append(scopes, makeScope[SharePointScope](SharePointList, sites, lists, os...))
|
||||
|
||||
return scopes
|
||||
}
|
||||
|
||||
// ListItems produces one or more SharePoint list item scopes.
|
||||
// If any slice contains selectors.Any, that slice is reduced to [selectors.Any]
|
||||
// If any slice contains selectors.None, that slice is reduced to [selectors.None]
|
||||
// If any slice is empty, it defaults to [selectors.None]
|
||||
// options are only applied to the list scopes.
|
||||
func (s *sharePoint) ListItems(sites, lists, items []string, opts ...option) []SharePointScope {
|
||||
scopes := []SharePointScope{}
|
||||
|
||||
scopes = append(
|
||||
scopes,
|
||||
makeScope[SharePointScope](SharePointListItem, sites, items).
|
||||
set(SharePointList, lists, opts...),
|
||||
)
|
||||
|
||||
return scopes
|
||||
}
|
||||
@ -268,6 +313,8 @@ const (
|
||||
// types of data identified by SharePoint
|
||||
SharePointWebURL sharePointCategory = "SharePointWebURL"
|
||||
SharePointSite sharePointCategory = "SharePointSite"
|
||||
SharePointList sharePointCategory = "SharePointList"
|
||||
SharePointListItem sharePointCategory = "SharePointListItem"
|
||||
SharePointLibrary sharePointCategory = "SharePointLibrary"
|
||||
SharePointLibraryItem sharePointCategory = "SharePointLibraryItem"
|
||||
|
||||
@ -284,6 +331,10 @@ var sharePointLeafProperties = map[categorizer]leafProperty{
|
||||
pathKeys: []categorizer{SharePointSite},
|
||||
pathType: path.UnknownCategory,
|
||||
},
|
||||
SharePointListItem: {
|
||||
pathKeys: []categorizer{SharePointSite, SharePointList, SharePointListItem},
|
||||
pathType: path.ListsCategory,
|
||||
},
|
||||
}
|
||||
|
||||
func (c sharePointCategory) String() string {
|
||||
@ -299,6 +350,8 @@ func (c sharePointCategory) leafCat() categorizer {
|
||||
switch c {
|
||||
case SharePointLibrary, SharePointLibraryItem:
|
||||
return SharePointLibraryItem
|
||||
case SharePointList, SharePointListItem:
|
||||
return SharePointListItem
|
||||
}
|
||||
|
||||
return c
|
||||
@ -331,10 +384,19 @@ func (c sharePointCategory) isLeaf() bool {
|
||||
// [tenantID, service, siteID, category, folder, itemID]
|
||||
// => {spSite: siteID, spFolder: folder, spItemID: itemID}
|
||||
func (c sharePointCategory) pathValues(p path.Path) map[categorizer]string {
|
||||
var folderCat, itemCat categorizer
|
||||
|
||||
switch c {
|
||||
case SharePointLibrary, SharePointLibraryItem:
|
||||
folderCat, itemCat = SharePointLibrary, SharePointLibraryItem
|
||||
case SharePointList, SharePointListItem:
|
||||
folderCat, itemCat = SharePointList, SharePointListItem
|
||||
}
|
||||
|
||||
return map[categorizer]string{
|
||||
SharePointSite: p.ResourceOwner(),
|
||||
SharePointLibrary: p.Folder(),
|
||||
SharePointLibraryItem: p.Item(),
|
||||
SharePointSite: p.ResourceOwner(),
|
||||
folderCat: p.Folder(),
|
||||
itemCat: p.Item(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,7 +468,9 @@ func (s SharePointScope) Get(cat sharePointCategory) []string {
|
||||
// sets a value by category to the scope. Only intended for internal use.
|
||||
func (s SharePointScope) set(cat sharePointCategory, v []string, opts ...option) SharePointScope {
|
||||
os := []option{}
|
||||
if cat == SharePointLibrary {
|
||||
|
||||
switch cat {
|
||||
case SharePointLibrary, SharePointList:
|
||||
os = append(os, pathComparator())
|
||||
}
|
||||
|
||||
@ -419,8 +483,12 @@ func (s SharePointScope) setDefaults() {
|
||||
case SharePointSite:
|
||||
s[SharePointLibrary.String()] = passAny
|
||||
s[SharePointLibraryItem.String()] = passAny
|
||||
s[SharePointList.String()] = passAny
|
||||
s[SharePointListItem.String()] = passAny
|
||||
case SharePointLibrary:
|
||||
s[SharePointLibraryItem.String()] = passAny
|
||||
case SharePointList:
|
||||
s[SharePointListItem.String()] = passAny
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,7 +511,7 @@ func (s sharePoint) Reduce(ctx context.Context, deets *details.Details) *details
|
||||
s.Selector,
|
||||
map[path.CategoryType]sharePointCategory{
|
||||
path.LibrariesCategory: SharePointLibraryItem,
|
||||
// TODO: list category type
|
||||
path.ListsCategory: SharePointListItem,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Sites() {
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
require.Len(t, test.scopesToCheck, 1)
|
||||
require.Len(t, test.scopesToCheck, 2)
|
||||
for _, scope := range test.scopesToCheck {
|
||||
// Scope value is s1,s2
|
||||
assert.Contains(t, join(s1, s2), scope[SharePointSite.String()].Target)
|
||||
@ -129,7 +129,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Include_WebURLs() {
|
||||
|
||||
sel.Include(sel.WebURL([]string{s1, s2}))
|
||||
scopes := sel.Includes
|
||||
require.Len(t, scopes, 1)
|
||||
require.Len(t, scopes, 2)
|
||||
|
||||
for _, sc := range scopes {
|
||||
scopeMustHave(
|
||||
@ -162,7 +162,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Include_WebURLs_any
|
||||
sel := NewSharePointRestore()
|
||||
sel.Include(sel.WebURL(test.in))
|
||||
scopes := sel.Includes
|
||||
require.Len(t, scopes, 1)
|
||||
require.Len(t, scopes, 2)
|
||||
|
||||
for _, sc := range scopes {
|
||||
scopeMustHave(
|
||||
@ -186,7 +186,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Exclude_WebURLs() {
|
||||
|
||||
sel.Exclude(sel.WebURL([]string{s1, s2}))
|
||||
scopes := sel.Excludes
|
||||
require.Len(t, scopes, 1)
|
||||
require.Len(t, scopes, 2)
|
||||
|
||||
for _, sc := range scopes {
|
||||
scopeMustHave(
|
||||
@ -197,6 +197,8 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Exclude_WebURLs() {
|
||||
}
|
||||
}
|
||||
|
||||
// TestSharePointselector_Include_Sites ensures that the scopes of
|
||||
// SharePoint Libraries & SharePoint Lists are created.
|
||||
func (suite *SharePointSelectorSuite) TestSharePointSelector_Include_Sites() {
|
||||
t := suite.T()
|
||||
sel := NewSharePointBackup()
|
||||
@ -208,7 +210,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Include_Sites() {
|
||||
|
||||
sel.Include(sel.Sites([]string{s1, s2}))
|
||||
scopes := sel.Includes
|
||||
require.Len(t, scopes, 1)
|
||||
require.Len(t, scopes, 2)
|
||||
|
||||
for _, sc := range scopes {
|
||||
scopeMustHave(
|
||||
@ -230,7 +232,7 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Exclude_Sites() {
|
||||
|
||||
sel.Exclude(sel.Sites([]string{s1, s2}))
|
||||
scopes := sel.Excludes
|
||||
require.Len(t, scopes, 1)
|
||||
require.Len(t, scopes, 2)
|
||||
|
||||
for _, sc := range scopes {
|
||||
scopeMustHave(
|
||||
@ -352,18 +354,46 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
|
||||
|
||||
func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
|
||||
t := suite.T()
|
||||
|
||||
pathBuilder := path.Builder{}.Append("dir1", "dir2", "item")
|
||||
itemPath, err := pathBuilder.ToDataLayerSharePointPath("tenant", "site", path.LibrariesCategory, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := map[categorizer]string{
|
||||
SharePointSite: "site",
|
||||
SharePointLibrary: "dir1/dir2",
|
||||
SharePointLibraryItem: "item",
|
||||
ten := "tenant"
|
||||
site := "site"
|
||||
table := []struct {
|
||||
name string
|
||||
sc sharePointCategory
|
||||
expected map[categorizer]string
|
||||
}{
|
||||
{
|
||||
name: "SharePoint Libraries",
|
||||
sc: SharePointLibraryItem,
|
||||
expected: map[categorizer]string{
|
||||
SharePointSite: site,
|
||||
SharePointLibrary: "dir1/dir2",
|
||||
SharePointLibraryItem: "item",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SharePoint Lists",
|
||||
sc: SharePointListItem,
|
||||
expected: map[categorizer]string{
|
||||
SharePointSite: site,
|
||||
SharePointList: "dir1/dir2",
|
||||
SharePointListItem: "item",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, expected, SharePointLibraryItem.pathValues(itemPath))
|
||||
for _, test := range table {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
itemPath, err := pathBuilder.ToDataLayerSharePointPath(
|
||||
ten,
|
||||
site,
|
||||
test.sc.PathType(),
|
||||
true,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.expected, test.sc.pathValues(itemPath))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *SharePointSelectorSuite) TestSharePointScope_MatchesInfo() {
|
||||
@ -418,6 +448,7 @@ func (suite *SharePointSelectorSuite) TestCategory_PathType() {
|
||||
{SharePointSite, path.UnknownCategory},
|
||||
{SharePointLibrary, path.LibrariesCategory},
|
||||
{SharePointLibraryItem, path.LibrariesCategory},
|
||||
{SharePointList, path.ListsCategory},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.cat.String(), func(t *testing.T) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user