remove resource owners from scopes (#1895)

## Description
    
Now that resource owners are identified via
the selector itself, rather than each scope, we
can remove the resource owner data from
scope production and data.

## Does this PR need a docs update or release note?

- [x]  No 

## Type of change

- [x] 🌻 Feature

## Issue(s)

* #1617

## Test Plan

- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2023-01-05 14:29:48 -07:00 committed by GitHub
parent 70d5a5ab56
commit 2b45cfa617
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 429 additions and 593 deletions

View File

@ -326,19 +326,19 @@ func exchangeBackupCreateSelectors(userIDs, data []string) *selectors.ExchangeBa
sel := selectors.NewExchangeBackup(userIDs)
if len(data) == 0 {
sel.Include(sel.ContactFolders(userIDs, selectors.Any()))
sel.Include(sel.MailFolders(userIDs, selectors.Any()))
sel.Include(sel.EventCalendars(userIDs, selectors.Any()))
sel.Include(sel.ContactFolders(selectors.Any()))
sel.Include(sel.MailFolders(selectors.Any()))
sel.Include(sel.EventCalendars(selectors.Any()))
}
for _, d := range data {
switch d {
case dataContacts:
sel.Include(sel.ContactFolders(userIDs, selectors.Any()))
sel.Include(sel.ContactFolders(selectors.Any()))
case dataEmail:
sel.Include(sel.MailFolders(userIDs, selectors.Any()))
sel.Include(sel.MailFolders(selectors.Any()))
case dataEvents:
sel.Include(sel.EventCalendars(userIDs, selectors.Any()))
sel.Include(sel.EventCalendars(selectors.Any()))
}
}
@ -510,7 +510,7 @@ func runDetailsExchangeCmd(
// if no selector flags were specified, get all data in the service.
if len(sel.Scopes()) == 0 {
sel.Include(sel.Users(selectors.Any()))
sel.Include(sel.AllData())
}
return sel.Reduce(ctx, d), nil

View File

@ -275,16 +275,13 @@ func (suite *PreparedBackupExchangeIntegrationSuite) SetupSuite() {
switch set {
case email:
scopes = sel.MailFolders(users, []string{exchange.DefaultMailFolder}, selectors.PrefixMatch())
scopes = sel.MailFolders([]string{exchange.DefaultMailFolder}, selectors.PrefixMatch())
case contacts:
scopes = sel.ContactFolders(
users,
[]string{exchange.DefaultContactFolder},
selectors.PrefixMatch())
scopes = sel.ContactFolders([]string{exchange.DefaultContactFolder}, selectors.PrefixMatch())
case events:
scopes = sel.EventCalendars(users, []string{exchange.DefaultCalendar}, selectors.PrefixMatch())
scopes = sel.EventCalendars([]string{exchange.DefaultCalendar}, selectors.PrefixMatch())
}
sel.Include(scopes)
@ -497,7 +494,7 @@ func (suite *BackupDeleteExchangeIntegrationSuite) SetupSuite() {
// some tests require an existing backup
sel := selectors.NewExchangeBackup(users)
sel.Include(sel.MailFolders(users, []string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
sel.Include(sel.MailFolders([]string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
suite.backupOp, err = suite.repo.NewBackup(ctx, sel.Selector)
require.NoError(t, suite.backupOp.Run(ctx))

View File

@ -254,7 +254,7 @@ func validateOneDriveBackupCreateFlags(users []string) error {
func oneDriveBackupCreateSelectors(users []string) *selectors.OneDriveBackup {
sel := selectors.NewOneDriveBackup(users)
sel.Include(sel.Users(users))
sel.Include(sel.AllData())
return sel
}
@ -401,7 +401,7 @@ func runDetailsOneDriveCmd(
// if no selector flags were specified, get all data in the service.
if len(sel.Scopes()) == 0 {
sel.Include(sel.Users(selectors.Any()))
sel.Include(sel.AllData())
}
return sel.Reduce(ctx, d), nil

View File

@ -160,7 +160,7 @@ func (suite *BackupDeleteOneDriveIntegrationSuite) SetupSuite() {
// some tests require an existing backup
sel := selectors.NewOneDriveBackup(users)
sel.Include(sel.Folders(users, selectors.Any()))
sel.Include(sel.Folders(selectors.Any()))
suite.backupOp, err = suite.repo.NewBackup(ctx, sel.Selector)
require.NoError(t, suite.backupOp.Run(ctx))

View File

@ -263,6 +263,7 @@ func validateSharePointBackupCreateFlags(sites, weburls []string) error {
return nil
}
// TODO: users might specify a data type, this only supports AllData().
func sharePointBackupCreateSelectors(
ctx context.Context,
sites, weburls []string,
@ -275,7 +276,7 @@ func sharePointBackupCreateSelectors(
for _, site := range sites {
if site == utils.Wildcard {
sel := selectors.NewSharePointBackup(selectors.Any())
sel.Include(sel.Sites(selectors.Any()))
sel.Include(sel.AllData())
return sel, nil
}
@ -284,7 +285,7 @@ func sharePointBackupCreateSelectors(
for _, wURL := range weburls {
if wURL == utils.Wildcard {
sel := selectors.NewSharePointBackup(selectors.Any())
sel.Include(sel.Sites(selectors.Any()))
sel.Include(sel.AllData())
return sel, nil
}
@ -296,7 +297,7 @@ func sharePointBackupCreateSelectors(
}
sel := selectors.NewSharePointBackup(union)
sel.Include(sel.Sites(union))
sel.Include(sel.AllData())
return sel, nil
}
@ -484,7 +485,7 @@ func runDetailsSharePointCmd(
// if no selector flags were specified, get all data in the service.
if len(sel.Scopes()) == 0 {
sel.Include(sel.Sites(selectors.Any()))
sel.Include(sel.AllData())
}
return sel.Reduce(ctx, d), nil

View File

@ -156,7 +156,7 @@ func (suite *BackupDeleteSharePointIntegrationSuite) SetupSuite() {
// some tests require an existing backup
sel := selectors.NewSharePointBackup(sites)
sel.Include(sel.Libraries(sites, selectors.Any()))
sel.Include(sel.Libraries(selectors.Any()))
suite.backupOp, err = suite.repo.NewBackup(ctx, sel.Selector)
require.NoError(t, suite.backupOp.Run(ctx))

View File

@ -189,15 +189,7 @@ func (suite *SharePointSuite) TestSharePointBackupCreateSelectors() {
sel, err := sharePointBackupCreateSelectors(ctx, test.site, test.weburl, gc)
require.NoError(t, err)
scopes := sel.Scopes()
assert.Len(t, scopes, test.expectScopesLen)
if test.expectScopesLen == 0 {
return
}
targetSites := scopes[0].Get(selectors.SharePointSite)
assert.ElementsMatch(t, test.expect, targetSites)
assert.ElementsMatch(t, test.expect, sel.DiscreteResourceOwners())
})
}
}

View File

@ -200,14 +200,9 @@ func connectS3Cmd(cmd *cobra.Command, args []string) error {
}
func s3Overrides() map[string]string {
var (
prvM365 = account.ProviderM365.String()
prvS3 = storage.ProviderS3.String()
)
return map[string]string{
config.AccountProviderTypeKey: prvM365,
config.StorageProviderTypeKey: prvS3,
config.AccountProviderTypeKey: account.ProviderM365.String(),
config.StorageProviderTypeKey: storage.ProviderS3.String(),
storage.Bucket: bucket,
storage.Endpoint: endpoint,
storage.Prefix: prefix,

View File

@ -12,7 +12,6 @@ import (
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/repository"
"github.com/alcionai/corso/src/pkg/selectors"
)
// exchange bucket info from flags
@ -221,7 +220,7 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
// if no selector flags were specified, get all data in the service.
if len(sel.Scopes()) == 0 {
sel.Include(sel.Users(selectors.Any()))
sel.Include(sel.AllData())
}
restoreDest := control.DefaultRestoreDestination(common.SimpleDateTime)

View File

@ -90,16 +90,13 @@ func (suite *RestoreExchangeIntegrationSuite) SetupSuite() {
switch set {
case email:
scopes = sel.MailFolders(users, []string{exchange.DefaultMailFolder}, selectors.PrefixMatch())
scopes = sel.MailFolders([]string{exchange.DefaultMailFolder}, selectors.PrefixMatch())
case contacts:
scopes = sel.ContactFolders(
users,
[]string{exchange.DefaultContactFolder},
selectors.PrefixMatch())
scopes = sel.ContactFolders([]string{exchange.DefaultContactFolder}, selectors.PrefixMatch())
case events:
scopes = sel.EventCalendars(users, []string{exchange.DefaultCalendar}, selectors.PrefixMatch())
scopes = sel.EventCalendars([]string{exchange.DefaultCalendar}, selectors.PrefixMatch())
}
sel.Include(scopes)

View File

@ -12,7 +12,6 @@ import (
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/repository"
"github.com/alcionai/corso/src/pkg/selectors"
)
var (
@ -158,7 +157,7 @@ func restoreOneDriveCmd(cmd *cobra.Command, args []string) error {
// if no selector flags were specified, get all data in the service.
if len(sel.Scopes()) == 0 {
sel.Include(sel.Users(selectors.Any()))
sel.Include(sel.AllData())
}
restoreDest := control.DefaultRestoreDestination(common.SimpleDateTimeOneDrive)

View File

@ -12,7 +12,6 @@ import (
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/repository"
"github.com/alcionai/corso/src/pkg/selectors"
)
var (
@ -159,7 +158,7 @@ func restoreSharePointCmd(cmd *cobra.Command, args []string) error {
// if no selector flags were specified, get all data in the service.
if len(sel.Scopes()) == 0 {
sel.Include(sel.Sites(selectors.Any()))
sel.Include(sel.AllData())
}
restoreDest := control.DefaultRestoreDestination(common.SimpleDateTimeOneDrive)

View File

@ -53,7 +53,7 @@ type ExchangeOpts struct {
// to act as a wildcard.
func AddExchangeInclude(
sel *selectors.ExchangeRestore,
resource, folders, items []string,
folders, items []string,
eisc selectors.ExchangeItemScopeConstructor,
) {
lf, li := len(folders), len(items)
@ -64,10 +64,6 @@ func AddExchangeInclude(
return
}
if len(resource) == 0 {
resource = selectors.Any()
}
if li == 0 {
items = selectors.Any()
}
@ -75,11 +71,11 @@ func AddExchangeInclude(
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(folders)
if len(containsFolders) > 0 {
sel.Include(eisc(resource, containsFolders, items))
sel.Include(eisc(containsFolders, items))
}
if len(prefixFolders) > 0 {
sel.Include(eisc(resource, prefixFolders, items, selectors.PrefixMatch()))
sel.Include(eisc(prefixFolders, items, selectors.PrefixMatch()))
}
}
@ -141,7 +137,7 @@ func IncludeExchangeRestoreDataSelectors(opts ExchangeOpts) *selectors.ExchangeR
lev, lec := len(opts.Event), len(opts.EventCalendar)
// either scope the request to a set of users
if lc+lcf+le+lef+lev+lec == 0 {
sel.Include(sel.Users(users))
sel.Include(sel.AllData())
return sel
}
@ -149,9 +145,9 @@ func IncludeExchangeRestoreDataSelectors(opts ExchangeOpts) *selectors.ExchangeR
opts.EmailFolder = trimFolderSlash(opts.EmailFolder)
// or add selectors for each type of data
AddExchangeInclude(sel, users, opts.ContactFolder, opts.Contact, sel.Contacts)
AddExchangeInclude(sel, users, opts.EmailFolder, opts.Email, sel.Mails)
AddExchangeInclude(sel, users, opts.EventCalendar, opts.Event, sel.Events)
AddExchangeInclude(sel, opts.ContactFolder, opts.Contact, sel.Contacts)
AddExchangeInclude(sel, opts.EmailFolder, opts.Email, sel.Mails)
AddExchangeInclude(sel, opts.EventCalendar, opts.Event, sel.Events)
return sel
}

View File

@ -370,7 +370,7 @@ func (suite *ExchangeUtilsSuite) TestAddExchangeInclude() {
suite.T().Run(test.name, func(t *testing.T) {
sel := selectors.NewExchangeRestore(nil)
// no return, mutates sel as a side effect
utils.AddExchangeInclude(sel, test.resources, test.folders, test.items, eisc)
utils.AddExchangeInclude(sel, test.folders, test.items, eisc)
assert.Len(t, sel.Includes, test.expectIncludeLen)
})
}

View File

@ -83,7 +83,7 @@ func IncludeOneDriveRestoreDataSelectors(opts OneDriveOpts) *selectors.OneDriveR
// only use the inclusion if either a path or item name
// is specified
if lp+ln == 0 {
sel.Include(sel.Users(opts.Users))
sel.Include(sel.AllData())
return sel
}
@ -97,11 +97,11 @@ func IncludeOneDriveRestoreDataSelectors(opts OneDriveOpts) *selectors.OneDriveR
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.Paths)
if len(containsFolders) > 0 {
sel.Include(sel.Items(users, containsFolders, opts.Names))
sel.Include(sel.Items(containsFolders, opts.Names))
}
if len(prefixFolders) > 0 {
sel.Include(sel.Items(users, prefixFolders, opts.Names, selectors.PrefixMatch()))
sel.Include(sel.Items(prefixFolders, opts.Names, selectors.PrefixMatch()))
}
return sel

View File

@ -68,7 +68,7 @@ func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.Share
sel := selectors.NewSharePointRestore(sites)
if lp+li+lwu+slp+sli == 0 {
sel.Include(sel.Sites(sites))
sel.Include(sel.AllData())
return sel
}
@ -81,11 +81,11 @@ func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.Share
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.LibraryPaths)
if len(containsFolders) > 0 {
sel.Include(sel.LibraryItems(sites, containsFolders, opts.LibraryItems))
sel.Include(sel.LibraryItems(containsFolders, opts.LibraryItems))
}
if len(prefixFolders) > 0 {
sel.Include(sel.LibraryItems(sites, prefixFolders, opts.LibraryItems, selectors.PrefixMatch()))
sel.Include(sel.LibraryItems(prefixFolders, opts.LibraryItems, selectors.PrefixMatch()))
}
}
@ -98,11 +98,11 @@ func IncludeSharePointRestoreDataSelectors(opts SharePointOpts) *selectors.Share
containsFolders, prefixFolders := splitFoldersIntoContainsAndPrefix(opts.ListPaths)
if len(containsFolders) > 0 {
sel.Include(sel.ListItems(opts.Sites, containsFolders, opts.ListItems))
sel.Include(sel.ListItems(containsFolders, opts.ListItems))
}
if len(prefixFolders) > 0 {
sel.Include(sel.ListItems(opts.Sites, prefixFolders, opts.ListItems, selectors.PrefixMatch()))
sel.Include(sel.ListItems(prefixFolders, opts.ListItems, selectors.PrefixMatch()))
}
}

View File

@ -106,14 +106,18 @@ func verifyBackupInputs(sels selectors.Selector, userPNs, siteIDs []string) erro
ids = siteIDs
}
// verify resourceOwners
normROs := map[string]struct{}{}
resourceOwner := strings.ToLower(sels.DiscreteOwner)
var found bool
for _, id := range ids {
normROs[strings.ToLower(id)] = struct{}{}
if strings.ToLower(id) == resourceOwner {
found = true
break
}
}
if _, ok := normROs[strings.ToLower(sels.DiscreteOwner)]; !ok {
if !found {
return fmt.Errorf("resource owner [%s] not found within tenant", sels.DiscreteOwner)
}

View File

@ -70,7 +70,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestExchangeDataCollection
name: suite.user + " Email",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup(selUsers)
sel.Include(sel.MailFolders(selUsers, []string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
sel.Include(sel.MailFolders([]string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
sel.DiscreteOwner = suite.user
return sel.Selector
},
@ -79,7 +79,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestExchangeDataCollection
name: suite.user + " Contacts",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup(selUsers)
sel.Include(sel.ContactFolders(selUsers, []string{exchange.DefaultContactFolder}, selectors.PrefixMatch()))
sel.Include(sel.ContactFolders([]string{exchange.DefaultContactFolder}, selectors.PrefixMatch()))
sel.DiscreteOwner = suite.user
return sel.Selector
},
@ -88,7 +88,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestExchangeDataCollection
// name: suite.user + " Events",
// getSelector: func(t *testing.T) selectors.Selector {
// sel := selectors.NewExchangeBackup(selUsers)
// sel.Include(sel.EventCalendars(selUsers, []string{exchange.DefaultCalendar}, selectors.PrefixMatch()))
// sel.Include(sel.EventCalendars([]string{exchange.DefaultCalendar}, selectors.PrefixMatch()))
// sel.DiscreteOwner = suite.user
// return sel.Selector
// },
@ -146,7 +146,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
name: "invalid exchange backup user",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup(owners)
sel.Include(sel.MailFolders(owners, selectors.Any()))
sel.Include(sel.MailFolders(selectors.Any()))
return sel.Selector
},
},
@ -154,7 +154,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
name: "Invalid onedrive backup user",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup(owners)
sel.Include(sel.Folders(owners, selectors.Any()))
sel.Include(sel.Folders(selectors.Any()))
return sel.Selector
},
},
@ -162,7 +162,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
name: "Invalid sharepoint backup site",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup(owners)
sel.Include(sel.Libraries(owners, selectors.Any()))
sel.Include(sel.Libraries(selectors.Any()))
return sel.Selector
},
},
@ -170,7 +170,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
name: "missing exchange backup user",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup(owners)
sel.Include(sel.MailFolders(owners, selectors.Any()))
sel.Include(sel.MailFolders(selectors.Any()))
sel.DiscreteOwner = ""
return sel.Selector
},
@ -179,7 +179,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
name: "missing onedrive backup user",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup(owners)
sel.Include(sel.Folders(owners, selectors.Any()))
sel.Include(sel.Folders(selectors.Any()))
sel.DiscreteOwner = ""
return sel.Selector
},
@ -188,7 +188,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestDataCollections_invali
name: "missing sharepoint backup site",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup(owners)
sel.Include(sel.Libraries(owners, selectors.Any()))
sel.Include(sel.Libraries(selectors.Any()))
sel.DiscreteOwner = ""
return sel.Selector
},
@ -223,9 +223,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestSharePointDataCollecti
name: "Libraries",
getSelector: func() selectors.Selector {
sel := selectors.NewSharePointBackup(selSites)
sel.Include(sel.Libraries(selSites, selectors.Any()))
sel.DiscreteOwner = suite.site
sel.Include(sel.Libraries(selectors.Any()))
return sel.Selector
},
},
@ -234,9 +232,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestSharePointDataCollecti
expected: 0,
getSelector: func() selectors.Selector {
sel := selectors.NewSharePointBackup(selSites)
sel.Include(sel.Lists(selSites, selectors.Any()))
sel.DiscreteOwner = suite.site
sel.Include(sel.Lists(selectors.Any()))
return sel.Selector
},
},
@ -330,12 +326,7 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
comparator: assert.Equal,
sel: func() selectors.Selector {
sel := selectors.NewSharePointBackup(siteIDs)
sel.Include(sel.Libraries(
siteIDs,
[]string{"foo"},
selectors.PrefixMatch(),
))
sel.Include(sel.Libraries([]string{"foo"}, selectors.PrefixMatch()))
return sel.Selector
},
},
@ -344,11 +335,7 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
comparator: assert.Less,
sel: func() selectors.Selector {
sel := selectors.NewSharePointBackup(siteIDs)
sel.Include(sel.Lists(
siteIDs,
selectors.Any(),
selectors.PrefixMatch(), // without this option a SEG Fault occurs
))
sel.Include(sel.Lists(selectors.Any(), selectors.PrefixMatch()))
return sel.Selector
},

View File

@ -246,7 +246,6 @@ func (suite *DataCollectionsIntegrationSuite) TestMailFetch() {
{
name: "Folder Iterative Check Mail",
scope: selectors.NewExchangeBackup(users).MailFolders(
users,
[]string{DefaultMailFolder},
selectors.PrefixMatch(),
)[0],
@ -303,7 +302,6 @@ func (suite *DataCollectionsIntegrationSuite) TestDelta() {
{
name: "Mail",
scope: selectors.NewExchangeBackup(users).MailFolders(
[]string{userID},
[]string{DefaultMailFolder},
selectors.PrefixMatch(),
)[0],
@ -311,7 +309,6 @@ func (suite *DataCollectionsIntegrationSuite) TestDelta() {
{
name: "Contacts",
scope: selectors.NewExchangeBackup(users).ContactFolders(
[]string{userID},
[]string{DefaultContactFolder},
selectors.PrefixMatch(),
)[0],
@ -391,7 +388,7 @@ func (suite *DataCollectionsIntegrationSuite) TestMailSerializationRegression()
require.NoError(t, err)
sel := selectors.NewExchangeBackup(users)
sel.Include(sel.MailFolders(users, []string{DefaultMailFolder}, selectors.PrefixMatch()))
sel.Include(sel.MailFolders([]string{DefaultMailFolder}, selectors.PrefixMatch()))
collections, err := createCollections(
ctx,
@ -451,7 +448,6 @@ func (suite *DataCollectionsIntegrationSuite) TestContactSerializationRegression
{
name: "Default Contact Folder",
scope: selectors.NewExchangeBackup(users).ContactFolders(
users,
[]string{DefaultContactFolder},
selectors.PrefixMatch())[0],
},
@ -528,7 +524,6 @@ func (suite *DataCollectionsIntegrationSuite) TestEventsSerializationRegression(
name: "Default Event Calendar",
expected: DefaultCalendar,
scope: selectors.NewExchangeBackup(users).EventCalendars(
users,
[]string{DefaultCalendar},
selectors.PrefixMatch())[0],
},
@ -536,7 +531,6 @@ func (suite *DataCollectionsIntegrationSuite) TestEventsSerializationRegression(
name: "Birthday Calendar",
expected: "Birthdays",
scope: selectors.NewExchangeBackup(users).EventCalendars(
users,
[]string{"Birthdays"},
selectors.PrefixMatch())[0],
},

View File

@ -216,8 +216,8 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs() {
name: "Valid Single User",
checkError: assert.NoError,
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup([]string{"bobkelso@someHospital.org"})
sel.Include(sel.MailFolders([]string{"bobkelso@someHospital.org"}, selectors.Any()))
sel := selectors.NewExchangeBackup([]string{"bobKelso@someHospital.org"})
sel.Include(sel.MailFolders(selectors.Any()))
return sel.Selector
},
},
@ -226,11 +226,20 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs() {
checkError: assert.Error,
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup([]string{"bobkelso@someHospital.org", "janitor@someHospital.org"})
sel.Include(sel.MailFolders([]string{"bobkelso@someHospital.org", "janitor@someHospital.org"}, selectors.Any()))
sel.Include(sel.MailFolders(selectors.Any()))
sel.DiscreteOwner = "janitor@someHospital.org"
return sel.Selector
},
},
{
name: "Invalid discrete owner",
checkError: assert.Error,
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"janitor@someHospital.org"})
sel.Include(sel.AllData())
return sel.Selector
},
},
}
for _, test := range tests {
@ -257,19 +266,19 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs_allServices
checkError: assert.NoError,
excludes: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"elliotReid@someHospital.org", "foo@SomeCompany.org"})
sel.Exclude(sel.Folders([]string{"elliotReid@someHospital.org"}, selectors.Any()))
sel.Exclude(sel.Folders(selectors.Any()))
sel.DiscreteOwner = "elliotReid@someHospital.org"
return sel.Selector
},
filters: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"elliotReid@someHospital.org", "foo@SomeCompany.org"})
sel.Filter(sel.Folders([]string{"elliotReid@someHospital.org"}, selectors.Any()))
sel.Filter(sel.Folders(selectors.Any()))
sel.DiscreteOwner = "elliotReid@someHospital.org"
return sel.Selector
},
includes: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"elliotReid@someHospital.org", "foo@SomeCompany.org"})
sel.Include(sel.Folders([]string{"elliotReid@someHospital.org"}, selectors.Any()))
sel.Include(sel.Folders(selectors.Any()))
sel.DiscreteOwner = "elliotReid@someHospital.org"
return sel.Selector
},
@ -279,17 +288,17 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs_allServices
checkError: assert.Error,
excludes: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"foo@SomeCompany.org"})
sel.Exclude(sel.Folders([]string{"foo@SomeCompany.org"}, selectors.Any()))
sel.Exclude(sel.Folders(selectors.Any()))
return sel.Selector
},
filters: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"foo@SomeCompany.org"})
sel.Filter(sel.Folders([]string{"foo@SomeCompany.org"}, selectors.Any()))
sel.Filter(sel.Folders(selectors.Any()))
return sel.Selector
},
includes: func(t *testing.T) selectors.Selector {
sel := selectors.NewOneDriveBackup([]string{"foo@SomeCompany.org"})
sel.Include(sel.Folders([]string{"foo@SomeCompany.org"}, selectors.Any()))
sel.Include(sel.Folders(selectors.Any()))
return sel.Selector
},
},
@ -298,20 +307,20 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs_allServices
checkError: assert.NoError,
excludes: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"abc.site.foo", "bar.site.baz"})
sel.Exclude(sel.Sites([]string{"abc.site.foo", "bar.site.baz"}))
sel.DiscreteOwner = "abc.site.foo"
sel.Exclude(sel.AllData())
return sel.Selector
},
filters: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"abc.site.foo", "bar.site.baz"})
sel.Filter(sel.Sites([]string{"abc.site.foo", "bar.site.baz"}))
sel.DiscreteOwner = "abc.site.foo"
sel.Filter(sel.AllData())
return sel.Selector
},
includes: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"abc.site.foo", "bar.site.baz"})
sel.Include(sel.Sites([]string{"abc.site.foo", "bar.site.baz"}))
sel.DiscreteOwner = "abc.site.foo"
sel.Include(sel.AllData())
return sel.Selector
},
},
@ -320,20 +329,17 @@ func (suite *DisconnectedGraphConnectorSuite) TestVerifyBackupInputs_allServices
checkError: assert.Error,
excludes: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"fnords.smarfs.brawnhilda"})
sel.Exclude(sel.Sites([]string{"fnords.smarfs.brawnhilda"}))
sel.DiscreteOwner = "fnords.smarfs.brawnhilda"
sel.Exclude(sel.AllData())
return sel.Selector
},
filters: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"fnords.smarfs.brawnhilda"})
sel.Filter(sel.Sites([]string{"fnords.smarfs.brawnhilda"}))
sel.DiscreteOwner = "fnords.smarfs.brawnhilda"
sel.Filter(sel.AllData())
return sel.Selector
},
includes: func(t *testing.T) selectors.Selector {
sel := selectors.NewSharePointBackup([]string{"fnords.smarfs.brawnhilda"})
sel.Include(sel.Sites([]string{"fnords.smarfs.brawnhilda"}))
sel.DiscreteOwner = "fnords.smarfs.brawnhilda"
sel.Include(sel.AllData())
return sel.Selector
},
},

View File

@ -798,7 +798,6 @@ func makeExchangeBackupSel(
}
toInclude = append(toInclude, builder(
[]string{d.resourceOwner},
[]string{d.dest},
selectors.PrefixMatch(),
))
@ -826,7 +825,6 @@ func makeOneDriveBackupSel(
sel := selectors.NewOneDriveBackup(nil)
toInclude = append(toInclude, sel.Folders(
[]string{d.resourceOwner},
[]string{d.dest},
selectors.PrefixMatch(),
))

View File

@ -83,7 +83,7 @@ func (suite *OneDriveCollectionsSuite) TestGetCanonicalPath() {
}
func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
anyFolder := (&selectors.OneDriveBackup{}).Folders(selectors.Any(), selectors.Any())[0]
anyFolder := (&selectors.OneDriveBackup{}).Folders(selectors.Any())[0]
const (
tenant = "tenant"
@ -181,7 +181,7 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
driveItem("fileInFolder2", testBaseDrivePath+folderSub+folder, true, false, false),
driveItem("fileInPackage", testBaseDrivePath+pkg, true, false, false),
},
scope: (&selectors.OneDriveBackup{}).Folders(selectors.Any(), []string{"folder"})[0],
scope: (&selectors.OneDriveBackup{}).Folders([]string{"folder"})[0],
expect: assert.NoError,
expectedCollectionPaths: append(
expectedPathAsSlice(
@ -214,7 +214,7 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
driveItem("fileInPackage", testBaseDrivePath+pkg, true, false, false),
},
scope: (&selectors.OneDriveBackup{}).
Folders(selectors.Any(), []string{"/folder/subfolder"}, selectors.PrefixMatch())[0],
Folders([]string{"/folder/subfolder"}, selectors.PrefixMatch())[0],
expect: assert.NoError,
expectedCollectionPaths: expectedPathAsSlice(
suite.T(),
@ -237,7 +237,7 @@ func (suite *OneDriveCollectionsSuite) TestUpdateCollections() {
driveItem("fileInSubfolder", testBaseDrivePath+folderSub, true, false, false),
driveItem("fileInPackage", testBaseDrivePath+pkg, true, false, false),
},
scope: (&selectors.OneDriveBackup{}).Folders(selectors.Any(), []string{"folder/subfolder"})[0],
scope: (&selectors.OneDriveBackup{}).Folders([]string{"folder/subfolder"})[0],
expect: assert.NoError,
expectedCollectionPaths: expectedPathAsSlice(
suite.T(),

View File

@ -144,7 +144,7 @@ func (suite *OneDriveSuite) TestOneDriveNewCollections() {
service := loadTestService(t)
scope := selectors.
NewOneDriveBackup([]string{test.user}).
Users([]string{test.user})[0]
AllData()[0]
odcs, err := NewCollections(
creds.AzureTenantID,
test.user,

View File

@ -58,7 +58,6 @@ func DataCollections(
serv,
tenantID,
site,
scope,
su,
ctrlOpts)
if err != nil {
@ -90,41 +89,36 @@ func collectLists(
ctx context.Context,
serv graph.Servicer,
tenantID, siteID string,
scope selectors.SharePointScope,
updater statusUpdater,
ctrlOpts control.Options,
) ([]data.Collection, error) {
logger.Ctx(ctx).With("site", siteID).Debug("Creating SharePoint List Collections")
if scope.Matches(selectors.SharePointSite, siteID) {
spcs := make([]data.Collection, 0)
spcs := make([]data.Collection, 0)
tuples, err := preFetchLists(ctx, serv, siteID)
if err != nil {
return nil, err
}
for _, tuple := range tuples {
dir, err := path.Builder{}.Append(tuple.name).
ToDataLayerSharePointPath(
tenantID,
siteID,
path.ListsCategory,
false)
if err != nil {
return nil, errors.Wrapf(err, "failed to create collection path for site: %s", siteID)
}
collection := NewCollection(dir, serv, updater.UpdateStatus)
collection.AddJob(tuple.id)
spcs = append(spcs, collection)
}
return spcs, nil
tuples, err := preFetchLists(ctx, serv, siteID)
if err != nil {
return nil, err
}
return nil, nil
for _, tuple := range tuples {
dir, err := path.Builder{}.Append(tuple.name).
ToDataLayerSharePointPath(
tenantID,
siteID,
path.ListsCategory,
false)
if err != nil {
return nil, errors.Wrapf(err, "failed to create collection path for site: %s", siteID)
}
collection := NewCollection(dir, serv, updater.UpdateStatus)
collection.AddJob(tuple.id)
spcs = append(spcs, collection)
}
return spcs, nil
}
// collectLibraries constructs a onedrive Collections struct and Get()s

View File

@ -46,7 +46,7 @@ func TestSharePointLibrariesSuite(t *testing.T) {
}
func (suite *SharePointLibrariesSuite) TestUpdateCollections() {
anyFolder := (&selectors.SharePointBackup{}).Libraries(selectors.Any(), selectors.Any())[0]
anyFolder := (&selectors.SharePointBackup{}).Libraries(selectors.Any())[0]
const (
tenant = "tenant"

View File

@ -515,7 +515,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchange() {
name: "Mail",
selector: func() *selectors.ExchangeBackup {
sel := selectors.NewExchangeBackup(users)
sel.Include(sel.MailFolders(users, []string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
sel.Include(sel.MailFolders([]string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
sel.DiscreteOwner = suite.user
return sel
@ -529,12 +529,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchange() {
name: "Contacts",
selector: func() *selectors.ExchangeBackup {
sel := selectors.NewExchangeBackup(users)
sel.Include(sel.ContactFolders(
users,
[]string{exchange.DefaultContactFolder},
selectors.PrefixMatch()))
sel.DiscreteOwner = suite.user
sel.Include(sel.ContactFolders([]string{exchange.DefaultContactFolder}, selectors.PrefixMatch()))
return sel
},
resourceOwner: suite.user,
@ -546,9 +541,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchange() {
name: "Calendar Events",
selector: func() *selectors.ExchangeBackup {
sel := selectors.NewExchangeBackup(users)
sel.Include(sel.EventCalendars(users, []string{exchange.DefaultCalendar}, selectors.PrefixMatch()))
sel.DiscreteOwner = suite.user
sel.Include(sel.EventCalendars([]string{exchange.DefaultCalendar}, selectors.PrefixMatch()))
return sel
},
resourceOwner: suite.user,
@ -755,8 +748,8 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchangeIncrementals() {
containers := []string{container1, container2, container3, containerRename}
sel := selectors.NewExchangeBackup(users)
sel.Include(
sel.MailFolders(users, containers, selectors.PrefixMatch()),
sel.ContactFolders(users, containers, selectors.PrefixMatch()),
sel.MailFolders(containers, selectors.PrefixMatch()),
sel.ContactFolders(containers, selectors.PrefixMatch()),
)
bo, _, kw, ms, closer := prepNewTestBackupOp(t, ctx, mb, sel.Selector, ffs)
@ -1015,7 +1008,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_oneDrive() {
sel = selectors.NewOneDriveBackup([]string{m365UserID})
)
sel.Include(sel.Users([]string{m365UserID}))
sel.Include(sel.AllData())
bo, _, _, _, closer := prepNewTestBackupOp(t, ctx, mb, sel.Selector, control.FeatureFlags{})
defer closer()
@ -1037,7 +1030,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_sharePoint() {
sel = selectors.NewSharePointBackup([]string{suite.site})
)
sel.Include(sel.Sites([]string{suite.site}))
sel.Include(sel.AllData())
bo, _, _, _, closer := prepNewTestBackupOp(t, ctx, mb, sel.Selector, control.FeatureFlags{})
defer closer()

View File

@ -180,9 +180,9 @@ func (suite *RestoreOpIntegrationSuite) SetupSuite() {
bsel := selectors.NewExchangeBackup(users)
bsel.DiscreteOwner = m365UserID
bsel.Include(
bsel.MailFolders(users, []string{exchange.DefaultMailFolder}, selectors.PrefixMatch()),
bsel.ContactFolders(users, []string{exchange.DefaultContactFolder}, selectors.PrefixMatch()),
bsel.EventCalendars(users, []string{exchange.DefaultCalendar}, selectors.PrefixMatch()),
bsel.MailFolders([]string{exchange.DefaultMailFolder}, selectors.PrefixMatch()),
bsel.ContactFolders([]string{exchange.DefaultContactFolder}, selectors.PrefixMatch()),
bsel.EventCalendars([]string{exchange.DefaultCalendar}, selectors.PrefixMatch()),
)
bo, err := NewBackupOperation(
@ -267,7 +267,7 @@ func (suite *RestoreOpIntegrationSuite) TestRestore_Run() {
users := []string{tester.M365UserID(t)}
rsel := selectors.NewExchangeRestore(users)
rsel.Include(rsel.Users(users))
rsel.Include(rsel.AllData())
dest := tester.DefaultTestRestoreDestination()
mb := evmock.NewBus()
@ -309,7 +309,7 @@ func (suite *RestoreOpIntegrationSuite) TestRestore_Run_ErrorNoResults() {
t := suite.T()
rsel := selectors.NewExchangeRestore(selectors.None())
rsel.Include(rsel.Users(selectors.None()))
rsel.Include(rsel.AllData())
dest := tester.DefaultTestRestoreDestination()
mb := evmock.NewBus()

View File

@ -26,7 +26,7 @@ func TestBackupSuite(t *testing.T) {
func stubBackup(t time.Time) backup.Backup {
sel := selectors.NewExchangeBackup(selectors.Any())
sel.Include(sel.Users(selectors.Any()))
sel.Include(sel.AllData())
return backup.Backup{
BaseModel: model.BaseModel{

View File

@ -396,9 +396,9 @@ func (suite *RepositoryLoadTestExchangeSuite) TestExchange() {
defer flush()
bsel := selectors.NewExchangeBackup(suite.usersUnderTest)
bsel.Include(bsel.MailFolders(suite.usersUnderTest, selectors.Any()))
bsel.Include(bsel.ContactFolders(suite.usersUnderTest, selectors.Any()))
bsel.Include(bsel.EventCalendars(suite.usersUnderTest, selectors.Any()))
bsel.Include(bsel.MailFolders(selectors.Any()))
bsel.Include(bsel.ContactFolders(selectors.Any()))
bsel.Include(bsel.EventCalendars(selectors.Any()))
sel := bsel.Selector
runLoadTest(
@ -444,9 +444,9 @@ func (suite *RepositoryIndividualLoadTestExchangeSuite) TestExchange() {
defer flush()
bsel := selectors.NewExchangeBackup(suite.usersUnderTest)
bsel.Include(bsel.MailFolders(suite.usersUnderTest, selectors.Any()))
bsel.Include(bsel.ContactFolders(suite.usersUnderTest, selectors.Any()))
bsel.Include(bsel.EventCalendars(suite.usersUnderTest, selectors.Any()))
bsel.Include(bsel.MailFolders(selectors.Any()))
bsel.Include(bsel.ContactFolders(selectors.Any()))
bsel.Include(bsel.EventCalendars(selectors.Any()))
sel := bsel.Selector
runLoadTest(
@ -494,7 +494,7 @@ func (suite *RepositoryLoadTestOneDriveSuite) TestOneDrive() {
defer flush()
bsel := selectors.NewOneDriveBackup(suite.usersUnderTest)
bsel.Include(bsel.Users(suite.usersUnderTest))
bsel.Include(bsel.AllData())
sel := bsel.Selector
runLoadTest(
@ -538,7 +538,7 @@ func (suite *RepositoryIndividualLoadTestOneDriveSuite) TestOneDrive() {
defer flush()
bsel := selectors.NewOneDriveBackup(suite.usersUnderTest)
bsel.Include(bsel.Users(suite.usersUnderTest))
bsel.Include(bsel.AllData())
sel := bsel.Selector
runLoadTest(
@ -586,7 +586,7 @@ func (suite *RepositoryLoadTestSharePointSuite) TestSharePoint() {
defer flush()
bsel := selectors.NewSharePointBackup(suite.sitesUnderTest)
bsel.Include(bsel.Sites(suite.sitesUnderTest))
bsel.Include(bsel.AllData())
sel := bsel.Selector
runLoadTest(
@ -630,7 +630,7 @@ func (suite *RepositoryIndividualLoadTestSharePointSuite) TestSharePoint() {
defer flush()
bsel := selectors.NewSharePointBackup(suite.sitesUnderTest)
bsel.Include(bsel.Sites(suite.sitesUnderTest))
bsel.Include(bsel.AllData())
sel := bsel.Selector
runLoadTest(

View File

@ -66,19 +66,19 @@ func Example_includeFoldersAndItems() {
// structures and individual items below. Higher level scopes will automatically
// involve all descendant data in the hierarchy.
// Users will select all Exchange data owned by the specified user.
seb.Users([]string{"foo-user-id"})
// AllData will select all Exchange data owned by the users specified
// in the selector.
seb.AllData()
// Lower level Scopes are described on a per-data-type basis. This scope will
// select all email in the Inbox folder, for all users in the tenant.
seb.MailFolders(selectors.Any(), []string{"Inbox"})
seb.MailFolders([]string{"Inbox"})
// Folder-level scopes will, by default, include every folder whose name matches
// the provided value, regardless of its position in the hierarchy. If you want
// to restrict the scope to a specific path, you can use the PrefixMatch option.
// This scope selects all data in /foolder, but will skip /other/foolder.
seb.MailFolders(
selectors.Any(),
[]string{"foolder"},
selectors.PrefixMatch())
@ -86,7 +86,6 @@ func Example_includeFoldersAndItems() {
// selection for users and folders when specifying an item, but these ids are
// usually unique, and have a low chance of collision.
seb.Mails(
selectors.Any(),
selectors.Any(),
[]string{"item-id-1", "item-id-2"},
)
@ -114,11 +113,6 @@ func Example_filters() {
// But you can still make a compound filter by adding each scope individually.
ser.MailSubject("the answer to life, the universe, and everything"),
)
// Selectors can specify both Filter and Inclusion scopes. Now, not only will the
// data only include emails matching the filters above, it will only include emails
// owned by this one user.
ser.Include(ser.Users([]string{"foo-user-id"}))
}
var (
@ -155,7 +149,7 @@ func Example_reduceDetails() {
// We haven't added any scopes to our selector yet, so none of the data is retained.
fmt.Println("Before adding scopes:", len(filteredDetails.Entries))
ser.Include(ser.Mails([]string{"your-user-id"}, []string{"example"}, []string{"xyz"}))
ser.Include(ser.Mails([]string{"example"}, []string{"xyz"}))
ser.Filter(ser.MailSubject("the answer to life"))
// Now that we've selected our data, we should find a result.
@ -174,11 +168,7 @@ func Example_scopeMatching() {
NewExchangeBackup(
[]string{"your-user-id", "foo-user-id", "bar-user-id"},
).
Mails(
[]string{"id-1"},
[]string{"Inbox"},
selectors.Any(),
)[0]
Mails([]string{"Inbox"}, selectors.Any())[0]
// To compare data against a scope, you need to specify the category of data,
// and input the value to check.
@ -186,8 +176,8 @@ func Example_scopeMatching() {
fmt.Println("Matches the mail folder 'inbox':", result)
// Non-matching values will return false.
result = scope.Matches(selectors.ExchangeUser, "id-42")
fmt.Println("Matches the user by id 'id-42':", result)
result = scope.Matches(selectors.ExchangeMailFolder, "Archive")
fmt.Println("Matches the mail folder by display name 'Archive':", result)
// If you specify a category that doesn't belong to the expected
// data type, the result is always false, even if the underlying
@ -201,7 +191,7 @@ func Example_scopeMatching() {
fmt.Println("Scope Category:", cat)
// Output: Matches the mail folder 'inbox': true
// Matches the user by id 'id-42': false
// Matches the mail folder by display name 'Archive': false
// Matches the contact by id 'id-1': false
// Scope Category: ExchangeMail
}

View File

@ -209,7 +209,7 @@ func (s *exchange) DiscreteScopes(userPNs []string) []ExchangeScope {
return ss
}
type ExchangeItemScopeConstructor func([]string, []string, []string, ...option) []ExchangeScope
type ExchangeItemScopeConstructor func([]string, []string, ...option) []ExchangeScope
// -------------------
// Scope Factories
@ -219,12 +219,12 @@ type ExchangeItemScopeConstructor func([]string, []string, []string, ...option)
// 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 folder scopes.
func (s *exchange) Contacts(users, folders, contacts []string, opts ...option) []ExchangeScope {
func (s *exchange) Contacts(folders, contacts []string, opts ...option) []ExchangeScope {
scopes := []ExchangeScope{}
scopes = append(
scopes,
makeScope[ExchangeScope](ExchangeContact, users, contacts).
makeScope[ExchangeScope](ExchangeContact, contacts).
set(ExchangeContactFolder, folders, opts...),
)
@ -236,7 +236,7 @@ func (s *exchange) Contacts(users, folders, contacts []string, opts ...option) [
// 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 folder scopes.
func (s *exchange) ContactFolders(users, folders []string, opts ...option) []ExchangeScope {
func (s *exchange) ContactFolders(folders []string, opts ...option) []ExchangeScope {
var (
scopes = []ExchangeScope{}
os = append([]option{pathComparator()}, opts...)
@ -244,7 +244,7 @@ func (s *exchange) ContactFolders(users, folders []string, opts ...option) []Exc
scopes = append(
scopes,
makeScope[ExchangeScope](ExchangeContactFolder, users, folders, os...),
makeScope[ExchangeScope](ExchangeContactFolder, folders, os...),
)
return scopes
@ -255,12 +255,12 @@ func (s *exchange) ContactFolders(users, folders []string, opts ...option) []Exc
// 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 folder scopes.
func (s *exchange) Events(users, calendars, events []string, opts ...option) []ExchangeScope {
func (s *exchange) Events(calendars, events []string, opts ...option) []ExchangeScope {
scopes := []ExchangeScope{}
scopes = append(
scopes,
makeScope[ExchangeScope](ExchangeEvent, users, events).
makeScope[ExchangeScope](ExchangeEvent, events).
set(ExchangeEventCalendar, calendars, opts...),
)
@ -273,7 +273,7 @@ func (s *exchange) Events(users, calendars, events []string, opts ...option) []E
// 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 folder scopes.
func (s *exchange) EventCalendars(users, events []string, opts ...option) []ExchangeScope {
func (s *exchange) EventCalendars(events []string, opts ...option) []ExchangeScope {
var (
scopes = []ExchangeScope{}
os = append([]option{pathComparator()}, opts...)
@ -281,7 +281,7 @@ func (s *exchange) EventCalendars(users, events []string, opts ...option) []Exch
scopes = append(
scopes,
makeScope[ExchangeScope](ExchangeEventCalendar, users, events, os...),
makeScope[ExchangeScope](ExchangeEventCalendar, events, os...),
)
return scopes
@ -292,12 +292,12 @@ func (s *exchange) EventCalendars(users, events []string, opts ...option) []Exch
// 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 folder scopes.
func (s *exchange) Mails(users, folders, mails []string, opts ...option) []ExchangeScope {
func (s *exchange) Mails(folders, mails []string, opts ...option) []ExchangeScope {
scopes := []ExchangeScope{}
scopes = append(
scopes,
makeScope[ExchangeScope](ExchangeMail, users, mails).
makeScope[ExchangeScope](ExchangeMail, mails).
set(ExchangeMailFolder, folders, opts...),
)
@ -309,7 +309,7 @@ func (s *exchange) Mails(users, folders, mails []string, opts ...option) []Excha
// 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 folder scopes.
func (s *exchange) MailFolders(users, folders []string, opts ...option) []ExchangeScope {
func (s *exchange) MailFolders(folders []string, opts ...option) []ExchangeScope {
var (
scopes = []ExchangeScope{}
os = append([]option{pathComparator()}, opts...)
@ -317,24 +317,24 @@ func (s *exchange) MailFolders(users, folders []string, opts ...option) []Exchan
scopes = append(
scopes,
makeScope[ExchangeScope](ExchangeMailFolder, users, folders, os...),
makeScope[ExchangeScope](ExchangeMailFolder, folders, os...),
)
return scopes
}
// Produces one or more exchange contact user scopes.
// Retrieves all exchange data.
// Each user id generates three scopes, one for each data type: contact, event, and mail.
// 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]
func (s *exchange) Users(users []string) []ExchangeScope {
func (s *exchange) AllData() []ExchangeScope {
scopes := []ExchangeScope{}
scopes = append(scopes,
makeScope[ExchangeScope](ExchangeContactFolder, users, Any()),
makeScope[ExchangeScope](ExchangeEventCalendar, users, Any()),
makeScope[ExchangeScope](ExchangeMailFolder, users, Any()),
makeScope[ExchangeScope](ExchangeContactFolder, Any()),
makeScope[ExchangeScope](ExchangeEventCalendar, Any()),
makeScope[ExchangeScope](ExchangeMailFolder, Any()),
)
return scopes
@ -529,15 +529,15 @@ const (
// exchangeLeafProperties describes common metadata of the leaf categories
var exchangeLeafProperties = map[categorizer]leafProperty{
ExchangeContact: {
pathKeys: []categorizer{ExchangeUser, ExchangeContactFolder, ExchangeContact},
pathKeys: []categorizer{ExchangeContactFolder, ExchangeContact},
pathType: path.ContactsCategory,
},
ExchangeEvent: {
pathKeys: []categorizer{ExchangeUser, ExchangeEventCalendar, ExchangeEvent},
pathKeys: []categorizer{ExchangeEventCalendar, ExchangeEvent},
pathType: path.EventsCategory,
},
ExchangeMail: {
pathKeys: []categorizer{ExchangeUser, ExchangeMailFolder, ExchangeMail},
pathKeys: []categorizer{ExchangeMailFolder, ExchangeMail},
pathType: path.EmailCategory,
},
ExchangeUser: { // the root category must be represented, even though it isn't a leaf
@ -618,9 +618,8 @@ func (ec exchangeCategory) pathValues(p path.Path) map[categorizer]string {
}
return map[categorizer]string{
ExchangeUser: p.ResourceOwner(),
folderCat: p.Folder(),
itemCat: p.Item(),
folderCat: p.Folder(),
itemCat: p.Item(),
}
}

View File

@ -68,7 +68,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Contacts() {
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.Contacts([]string{user}, []string{folder}, []string{c1, c2}))
sel.Exclude(sel.Contacts([]string{folder}, []string{c1, c2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
@ -76,7 +76,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Contacts() {
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeContactFolder: folder,
ExchangeContact: join(c1, c2),
},
@ -94,7 +93,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Contacts() {
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.Contacts([]string{user}, []string{folder}, []string{c1, c2}))
sel.Include(sel.Contacts([]string{folder}, []string{c1, c2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
@ -102,7 +101,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Contacts() {
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeContactFolder: folder,
ExchangeContact: join(c1, c2),
},
@ -121,7 +119,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_ContactFolders(
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.ContactFolders([]string{user}, []string{f1, f2}))
sel.Exclude(sel.ContactFolders([]string{f1, f2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
@ -129,7 +127,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_ContactFolders(
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeContactFolder: join(f1, f2),
ExchangeContact: AnyTgt,
},
@ -146,7 +143,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_ContactFolders(
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.ContactFolders([]string{user}, []string{f1, f2}))
sel.Include(sel.ContactFolders([]string{f1, f2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
@ -154,7 +151,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_ContactFolders(
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeContactFolder: join(f1, f2),
ExchangeContact: AnyTgt,
},
@ -174,7 +170,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Events() {
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.Events([]string{user}, []string{c1}, []string{e1, e2}))
sel.Exclude(sel.Events([]string{c1}, []string{e1, e2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
@ -182,7 +178,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Events() {
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeEventCalendar: c1,
ExchangeEvent: join(e1, e2),
},
@ -199,7 +194,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_EventCalendars(
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.EventCalendars([]string{user}, []string{c1, c2}))
sel.Exclude(sel.EventCalendars([]string{c1, c2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
@ -207,7 +202,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_EventCalendars(
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeEventCalendar: join(c1, c2),
ExchangeEvent: AnyTgt,
},
@ -225,7 +219,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Events() {
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.Events([]string{user}, []string{c1}, []string{e1, e2}))
sel.Include(sel.Events([]string{c1}, []string{e1, e2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
@ -233,7 +227,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Events() {
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeEventCalendar: c1,
ExchangeEvent: join(e1, e2),
},
@ -250,7 +243,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_EventCalendars(
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.EventCalendars([]string{user}, []string{c1, c2}))
sel.Include(sel.EventCalendars([]string{c1, c2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
@ -258,7 +251,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_EventCalendars(
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeEventCalendar: join(c1, c2),
ExchangeEvent: AnyTgt,
},
@ -276,7 +268,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Mails() {
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.Mails([]string{user}, []string{folder}, []string{m1, m2}))
sel.Exclude(sel.Mails([]string{folder}, []string{m1, m2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
@ -284,7 +276,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Mails() {
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeMailFolder: folder,
ExchangeMail: join(m1, m2),
},
@ -302,7 +293,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Mails() {
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.Mails([]string{user}, []string{folder}, []string{m1, m2}))
sel.Include(sel.Mails([]string{folder}, []string{m1, m2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
@ -310,7 +301,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Mails() {
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeMailFolder: folder,
ExchangeMail: join(m1, m2),
},
@ -329,7 +319,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_MailFolders() {
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.MailFolders([]string{user}, []string{f1, f2}))
sel.Exclude(sel.MailFolders([]string{f1, f2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
@ -337,7 +327,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_MailFolders() {
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeMailFolder: join(f1, f2),
ExchangeMail: AnyTgt,
},
@ -354,7 +343,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_MailFolders() {
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.MailFolders([]string{user}, []string{f1, f2}))
sel.Include(sel.MailFolders([]string{f1, f2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
@ -362,7 +351,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_MailFolders() {
t,
ExchangeScope(scopes[0]),
map[categorizer]string{
ExchangeUser: user,
ExchangeMailFolder: join(f1, f2),
ExchangeMail: AnyTgt,
},
@ -371,7 +359,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_MailFolders() {
assert.Equal(t, sel.Scopes()[0].Category(), ExchangeMailFolder)
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Users() {
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_AllData() {
t := suite.T()
const (
@ -380,17 +368,11 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Users() {
)
sel := NewExchangeBackup([]string{u1, u2})
sel.Exclude(sel.Users([]string{u1, u2}))
sel.Exclude(sel.AllData())
scopes := sel.Excludes
require.Len(t, scopes, 3)
for _, sc := range scopes {
scopeMustHave(
t,
ExchangeScope(sc),
map[categorizer]string{ExchangeUser: join(u1, u2)},
)
if sc[scopeKeyCategory].Compare(ExchangeContactFolder.String()) {
scopeMustHave(
t,
@ -425,7 +407,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Users() {
}
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Users() {
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_AllData() {
t := suite.T()
const (
@ -434,17 +416,11 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Users() {
)
sel := NewExchangeBackup([]string{u1, u2})
sel.Include(sel.Users([]string{u1, u2}))
sel.Include(sel.AllData())
scopes := sel.Includes
require.Len(t, scopes, 3)
for _, sc := range scopes {
scopeMustHave(
t,
ExchangeScope(sc),
map[categorizer]string{ExchangeUser: join(u1, u2)},
)
if sc[scopeKeyCategory].Compare(ExchangeContactFolder.String()) {
scopeMustHave(
t,
@ -481,7 +457,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Users() {
func (suite *ExchangeSelectorSuite) TestExchangeBackup_Scopes() {
eb := NewExchangeBackup(Any())
eb.Include(eb.Users(Any()))
eb.Include(eb.AllData())
scopes := eb.Scopes()
assert.Len(suite.T(), scopes, 3)
@ -489,7 +465,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeBackup_Scopes() {
for _, sc := range scopes {
cat := sc.Category()
suite.T().Run(cat.String(), func(t *testing.T) {
assert.True(t, sc.IsAny(ExchangeUser))
switch sc.Category() {
case ExchangeContactFolder:
assert.True(t, sc.IsAny(ExchangeContact))
@ -534,14 +509,15 @@ func (suite *ExchangeSelectorSuite) TestExchangeBackup_DiscreteScopes() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
eb := NewExchangeBackup(test.include)
eb.Include(eb.Users(test.include))
// todo: remove discreteScopes
// eb := NewExchangeBackup(test.include)
// eb.Include(eb.AllData())
scopes := eb.DiscreteScopes(test.discrete)
for _, sc := range scopes {
users := sc.Get(ExchangeUser)
assert.Equal(t, test.expect, users)
}
// scopes := eb.DiscreteScopes(test.discrete)
// for _, sc := range scopes {
// users := sc.Get(ExchangeUser)
// assert.Equal(t, test.expect, users)
// }
})
}
}
@ -626,7 +602,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_IncludesCategory() {
func (suite *ExchangeSelectorSuite) TestExchangeScope_Get() {
eb := NewExchangeBackup(Any())
eb.Include(eb.Users(Any()))
eb.Include(eb.AllData())
scopes := eb.Scopes()
@ -636,12 +612,10 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_Get() {
ExchangeEvent,
ExchangeMail,
ExchangeMailFolder,
ExchangeUser,
}
for _, test := range table {
suite.T().Run(test.String(), func(t *testing.T) {
for _, sc := range scopes {
assert.Equal(t, Any(), sc.Get(ExchangeUser))
switch sc.Category() {
case ExchangeContactFolder:
assert.Equal(t, Any(), sc.Get(ExchangeContact))
@ -790,28 +764,24 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesPath() {
shortRef string
expect assert.BoolAssertionFunc
}{
{"all user's items", es.Users(Any()), "", assert.True},
{"no user's items", es.Users(None()), "", assert.True},
{"matching user", es.Users([]string{usr}), "", assert.True},
{"non-matching user", es.Users([]string{"smarf"}), "", assert.True},
{"one of multiple users", es.Users([]string{"smarf", usr}), "", assert.True},
{"all folders", es.MailFolders(Any(), Any()), "", assert.True},
{"no folders", es.MailFolders(Any(), None()), "", assert.False},
{"matching folder", es.MailFolders(Any(), []string{fld1}), "", assert.True},
{"incomplete matching folder", es.MailFolders(Any(), []string{"mail"}), "", assert.False},
{"non-matching folder", es.MailFolders(Any(), []string{"smarf"}), "", assert.False},
{"non-matching folder substring", es.MailFolders(Any(), []string{fld1 + "_suffix"}), "", assert.False},
{"matching folder prefix", es.MailFolders(Any(), []string{fld1}, PrefixMatch()), "", assert.True},
{"incomplete folder prefix", es.MailFolders(Any(), []string{"mail"}, PrefixMatch()), "", assert.False},
{"matching folder substring", es.MailFolders(Any(), []string{"Folder"}), "", assert.False},
{"one of multiple folders", es.MailFolders(Any(), []string{"smarf", fld2}), "", assert.True},
{"all mail", es.Mails(Any(), Any(), Any()), "", assert.True},
{"no mail", es.Mails(Any(), Any(), None()), "", assert.False},
{"matching mail", es.Mails(Any(), Any(), []string{mail}), "", assert.True},
{"non-matching mail", es.Mails(Any(), Any(), []string{"smarf"}), "", assert.False},
{"one of multiple mails", es.Mails(Any(), Any(), []string{"smarf", mail}), "", assert.True},
{"mail short ref", es.Mails(Any(), Any(), []string{short}), short, assert.True},
{"non-leaf short ref", es.Mails([]string{short}, []string{short}, []string{"foo"}), short, assert.False},
{"all items", es.AllData(), "", assert.True},
{"all folders", es.MailFolders(Any()), "", assert.True},
{"no folders", es.MailFolders(None()), "", assert.False},
{"matching folder", es.MailFolders([]string{fld1}), "", assert.True},
{"incomplete matching folder", es.MailFolders([]string{"mail"}), "", assert.False},
{"non-matching folder", es.MailFolders([]string{"smarf"}), "", assert.False},
{"non-matching folder substring", es.MailFolders([]string{fld1 + "_suffix"}), "", assert.False},
{"matching folder prefix", es.MailFolders([]string{fld1}, PrefixMatch()), "", assert.True},
{"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},
{"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},
{"non-matching mail", es.Mails(Any(), []string{"smarf"}), "", assert.False},
{"one of multiple mails", es.Mails(Any(), []string{"smarf", mail}), "", assert.True},
{"mail short ref", es.Mails(Any(), []string{short}), short, assert.True},
{"non-leaf short ref", es.Mails([]string{short}, []string{"foo"}), short, assert.False},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
@ -839,7 +809,6 @@ func (suite *ExchangeSelectorSuite) TestIdPath() {
ExchangeContact,
stubPath(suite.T(), "uid", []string{"cFld", "cid"}, path.ContactsCategory),
map[exchangeCategory]string{
ExchangeUser: "uid",
ExchangeContactFolder: "cFld",
ExchangeContact: "cid",
},
@ -848,7 +817,6 @@ func (suite *ExchangeSelectorSuite) TestIdPath() {
ExchangeEvent,
stubPath(suite.T(), "uid", []string{"eCld", "eid"}, path.EventsCategory),
map[exchangeCategory]string{
ExchangeUser: "uid",
ExchangeEventCalendar: "eCld",
ExchangeEvent: "eid",
},
@ -857,7 +825,6 @@ func (suite *ExchangeSelectorSuite) TestIdPath() {
ExchangeMail,
stubPath(suite.T(), "uid", []string{"mFld", "mid"}, path.EmailCategory),
map[exchangeCategory]string{
ExchangeUser: "uid",
ExchangeMailFolder: "mFld",
ExchangeMail: "mid",
},
@ -923,7 +890,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Include(er.AllData())
return er
},
[]string{},
@ -933,7 +900,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contact),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Include(er.AllData())
return er
},
arr(contact),
@ -943,7 +910,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(event),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Include(er.AllData())
return er
},
arr(event),
@ -953,7 +920,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Include(er.AllData())
return er
},
arr(mail),
@ -963,7 +930,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Include(er.AllData())
return er
},
arr(contact, event, mail),
@ -973,7 +940,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.Contacts([]string{"uid"}, []string{"cfld"}, []string{"cid"}))
er.Include(er.Contacts([]string{"cfld"}, []string{"cid"}))
return er
},
arr(contact),
@ -983,7 +950,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contactInSubFolder, contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.ContactFolders([]string{"uid"}, []string{"cfld1/cfld2"}))
er.Include(er.ContactFolders([]string{"cfld1/cfld2"}))
return er
},
arr(contactInSubFolder),
@ -993,7 +960,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contactInSubFolder, contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.ContactFolders([]string{"uid"}, []string{"cfld1/cfld2"}, PrefixMatch()))
er.Include(er.ContactFolders([]string{"cfld1/cfld2"}, PrefixMatch()))
return er
},
arr(contactInSubFolder),
@ -1003,7 +970,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contactInSubFolder, contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.ContactFolders([]string{"uid"}, []string{"cfld2"}))
er.Include(er.ContactFolders([]string{"cfld2"}))
return er
},
arr(contactInSubFolder),
@ -1013,7 +980,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.Events([]string{"uid"}, []string{"ecld"}, []string{"eid"}))
er.Include(er.Events([]string{"ecld"}, []string{"eid"}))
return er
},
arr(event),
@ -1023,7 +990,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.Mails([]string{"uid"}, []string{"mfld"}, []string{"mid"}))
er.Include(er.Mails([]string{"mfld"}, []string{"mid"}))
return er
},
arr(mail),
@ -1033,8 +1000,8 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Exclude(er.Contacts([]string{"uid"}, []string{"cfld"}, []string{"cid"}))
er.Include(er.AllData())
er.Exclude(er.Contacts([]string{"cfld"}, []string{"cid"}))
return er
},
arr(event, mail),
@ -1044,8 +1011,8 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Exclude(er.Events([]string{"uid"}, []string{"ecld"}, []string{"eid"}))
er.Include(er.AllData())
er.Exclude(er.Events([]string{"ecld"}, []string{"eid"}))
return er
},
arr(contact, mail),
@ -1055,8 +1022,8 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Exclude(er.Mails([]string{"uid"}, []string{"mfld"}, []string{"mid"}))
er.Include(er.AllData())
er.Exclude(er.Mails([]string{"mfld"}, []string{"mid"}))
return er
},
arr(contact, event),
@ -1072,7 +1039,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
}(),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Include(er.AllData())
er.Filter(er.MailSubject("subj"))
return er
},
@ -1093,7 +1060,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
}(),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.Users(Any()))
er.Include(er.AllData())
er.Filter(er.MailSubject("subj"))
return er
},
@ -1116,10 +1083,10 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
func (suite *ExchangeSelectorSuite) TestScopesByCategory() {
var (
es = NewExchangeRestore(Any())
users = es.Users(Any())
contacts = es.ContactFolders(Any(), Any())
events = es.Events(Any(), Any(), Any())
mail = es.MailFolders(Any(), Any())
allData = es.AllData()
contacts = es.ContactFolders(Any())
events = es.EventCalendars(Any())
mail = es.MailFolders(Any())
)
type expect struct {
@ -1152,11 +1119,10 @@ func (suite *ExchangeSelectorSuite) TestScopesByCategory() {
scopes input
expect expect
}{
{"users: one of each", makeInput(users), expect{1, 1, 1}},
{"contacts only", makeInput(contacts), expect{1, 0, 0}},
{"events only", makeInput(events), expect{0, 1, 0}},
{"mail only", makeInput(mail), expect{0, 0, 1}},
{"all", makeInput(users, contacts, events, mail), expect{2, 2, 2}},
{"all", makeInput(allData, contacts, events, mail), expect{2, 2, 2}},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
@ -1179,11 +1145,10 @@ func (suite *ExchangeSelectorSuite) TestPasses() {
var (
es = NewExchangeRestore(Any()) // TODO: move into test and compose with each test value
anyUser = setScopesToDefault(es.Users(Any()))
noUser = setScopesToDefault(es.Users(None()))
mail = setScopesToDefault(es.Mails(Any(), Any(), []string{mid}))
otherMail = setScopesToDefault(es.Mails(Any(), Any(), []string{"smarf"}))
noMail = setScopesToDefault(es.Mails(Any(), Any(), None()))
otherMail = setScopesToDefault(es.Mails(Any(), []string{"smarf"}))
mail = setScopesToDefault(es.Mails(Any(), []string{mid}))
noMail = setScopesToDefault(es.Mails(Any(), None()))
allMail = setScopesToDefault(es.Mails(Any(), Any()))
pth = stubPath(suite.T(), "user", []string{"folder", mid}, path.EmailCategory)
)
@ -1193,23 +1158,15 @@ func (suite *ExchangeSelectorSuite) TestPasses() {
expect assert.BoolAssertionFunc
}{
{"empty", nil, nil, nil, assert.False},
{"in Any", nil, nil, anyUser, assert.True},
{"in None", nil, nil, noUser, assert.True},
{"in Mail", nil, nil, mail, assert.True},
{"in Other", nil, nil, otherMail, assert.False},
{"in no Mail", nil, nil, noMail, assert.False},
{"ex Any", anyUser, nil, anyUser, assert.False},
{"ex Any filter", anyUser, anyUser, nil, assert.False},
{"ex None", noUser, nil, anyUser, assert.False},
{"ex None filter mail", noUser, mail, nil, assert.False},
{"ex None filter any user", noUser, anyUser, nil, assert.False},
{"ex Mail", mail, nil, anyUser, assert.False},
{"ex Other", otherMail, nil, anyUser, assert.True},
{"ex None filter mail", allMail, mail, nil, assert.False},
{"ex Mail", mail, nil, allMail, assert.False},
{"ex Other", otherMail, nil, allMail, assert.True},
{"in and ex Mail", mail, nil, mail, assert.False},
{"filter Any", nil, anyUser, nil, assert.False},
{"filter None", nil, noUser, anyUser, assert.False},
{"filter Mail", nil, mail, anyUser, assert.True},
{"filter Other", nil, otherMail, anyUser, assert.False},
{"filter Mail", nil, mail, allMail, assert.True},
{"filter Other", nil, otherMail, allMail, assert.False},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
@ -1230,12 +1187,11 @@ func (suite *ExchangeSelectorSuite) TestContains() {
var (
es = NewExchangeRestore(Any()) // TODO: move into test and compose with each test value
anyUser = setScopesToDefault(es.Users(Any()))
noMail = setScopesToDefault(es.Mails(None(), None(), None()))
does = setScopesToDefault(es.Mails(Any(), Any(), []string{target}))
doesNot = setScopesToDefault(es.Mails(Any(), Any(), []string{"smarf"}))
wrongType = setScopesToDefault(es.Contacts(Any(), Any(), Any()))
wrongTypeGoodTarget = setScopesToDefault(es.Contacts(Any(), Any(), Any()))
noMail = setScopesToDefault(es.Mails(None(), None()))
does = setScopesToDefault(es.Mails(Any(), []string{target}))
doesNot = setScopesToDefault(es.Mails(Any(), []string{"smarf"}))
wrongType = setScopesToDefault(es.Contacts(Any(), Any()))
wrongTypeGoodTarget = setScopesToDefault(es.Contacts(Any(), Any()))
)
table := []struct {
@ -1243,7 +1199,6 @@ func (suite *ExchangeSelectorSuite) TestContains() {
scopes []ExchangeScope
expect assert.BoolAssertionFunc
}{
{"any user", anyUser, assert.True},
{"no mail", noMail, assert.False},
{"does contain", does, assert.True},
{"does not contain", doesNot, assert.False},
@ -1267,10 +1222,8 @@ func (suite *ExchangeSelectorSuite) TestContains() {
func (suite *ExchangeSelectorSuite) TestIsAny() {
var (
es = NewExchangeRestore(Any()) // TODO: move into test and compose with each test value
anyUser = setScopesToDefault(es.Users(Any()))
noUser = setScopesToDefault(es.Users(None()))
specificMail = setScopesToDefault(es.Mails(Any(), Any(), []string{"email"}))
anyMail = setScopesToDefault(es.Mails(Any(), Any(), Any()))
specificMail = setScopesToDefault(es.Mails(Any(), []string{"email"}))
anyMail = setScopesToDefault(es.Mails(Any(), Any()))
)
table := []struct {
@ -1279,8 +1232,6 @@ func (suite *ExchangeSelectorSuite) TestIsAny() {
cat exchangeCategory
expect assert.BoolAssertionFunc
}{
{"any user", anyUser, ExchangeUser, assert.True},
{"no user", noUser, ExchangeUser, assert.False},
{"specific mail", specificMail, ExchangeMail, assert.False},
{"any mail", anyMail, ExchangeMail, assert.True},
{"wrong category", anyMail, ExchangeEvent, assert.False},
@ -1324,19 +1275,16 @@ func (suite *ExchangeSelectorSuite) TestExchangeCategory_PathValues() {
contactPath := stubPath(t, "user", []string{"cfolder", "contactitem"}, path.ContactsCategory)
contactMap := map[categorizer]string{
ExchangeUser: contactPath.ResourceOwner(),
ExchangeContactFolder: contactPath.Folder(),
ExchangeContact: contactPath.Item(),
}
eventPath := stubPath(t, "user", []string{"ecalendar", "eventitem"}, path.EventsCategory)
eventMap := map[categorizer]string{
ExchangeUser: eventPath.ResourceOwner(),
ExchangeEventCalendar: eventPath.Folder(),
ExchangeEvent: eventPath.Item(),
}
mailPath := stubPath(t, "user", []string{"mfolder", "mailitem"}, path.EmailCategory)
mailMap := map[categorizer]string{
ExchangeUser: mailPath.ResourceOwner(),
ExchangeMailFolder: mailPath.Folder(),
ExchangeMail: mailPath.Item(),
}
@ -1358,9 +1306,9 @@ func (suite *ExchangeSelectorSuite) TestExchangeCategory_PathValues() {
}
func (suite *ExchangeSelectorSuite) TestExchangeCategory_PathKeys() {
contact := []categorizer{ExchangeUser, ExchangeContactFolder, ExchangeContact}
event := []categorizer{ExchangeUser, ExchangeEventCalendar, ExchangeEvent}
mail := []categorizer{ExchangeUser, ExchangeMailFolder, ExchangeMail}
contact := []categorizer{ExchangeContactFolder, ExchangeContact}
event := []categorizer{ExchangeEventCalendar, ExchangeEvent}
mail := []categorizer{ExchangeMailFolder, ExchangeMail}
user := []categorizer{ExchangeUser}
var empty []categorizer

View File

@ -205,15 +205,15 @@ func (s *oneDrive) DiscreteScopes(userPNs []string) []OneDriveScope {
// -------------------
// Scope Factories
// Produces one or more OneDrive user scopes.
// Retrieves all OneDrive data.
// One scope is created per user entry.
// 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]
func (s *oneDrive) Users(users []string) []OneDriveScope {
func (s *oneDrive) AllData() []OneDriveScope {
scopes := []OneDriveScope{}
scopes = append(scopes, makeScope[OneDriveScope](OneDriveFolder, users, Any()))
scopes = append(scopes, makeScope[OneDriveScope](OneDriveFolder, Any()))
return scopes
}
@ -223,7 +223,7 @@ func (s *oneDrive) Users(users []string) []OneDriveScope {
// 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 folder scopes.
func (s *oneDrive) Folders(users, folders []string, opts ...option) []OneDriveScope {
func (s *oneDrive) Folders(folders []string, opts ...option) []OneDriveScope {
var (
scopes = []OneDriveScope{}
os = append([]option{pathComparator()}, opts...)
@ -231,7 +231,7 @@ func (s *oneDrive) Folders(users, folders []string, opts ...option) []OneDriveSc
scopes = append(
scopes,
makeScope[OneDriveScope](OneDriveFolder, users, folders, os...),
makeScope[OneDriveScope](OneDriveFolder, folders, os...),
)
return scopes
@ -242,12 +242,12 @@ func (s *oneDrive) Folders(users, folders []string, opts ...option) []OneDriveSc
// 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 folder scopes.
func (s *oneDrive) Items(users, folders, items []string, opts ...option) []OneDriveScope {
func (s *oneDrive) Items(folders, items []string, opts ...option) []OneDriveScope {
scopes := []OneDriveScope{}
scopes = append(
scopes,
makeScope[OneDriveScope](OneDriveItem, users, items).
makeScope[OneDriveScope](OneDriveItem, items).
set(OneDriveFolder, folders, opts...),
)
@ -341,7 +341,7 @@ const (
// oneDriveLeafProperties describes common metadata of the leaf categories
var oneDriveLeafProperties = map[categorizer]leafProperty{
OneDriveItem: {
pathKeys: []categorizer{OneDriveUser, OneDriveFolder, OneDriveItem},
pathKeys: []categorizer{OneDriveFolder, OneDriveItem},
pathType: path.FilesCategory,
},
OneDriveUser: { // the root category must be represented, even though it isn't a leaf
@ -401,7 +401,6 @@ func (c oneDriveCategory) pathValues(p path.Path) map[categorizer]string {
folder := path.Builder{}.Append(p.Folders()...).PopFront().PopFront().PopFront().String()
return map[categorizer]string{
OneDriveUser: p.ResourceOwner(),
OneDriveFolder: folder,
OneDriveItem: p.Item(),
}

View File

@ -69,41 +69,34 @@ func (suite *OneDriveSelectorSuite) TestOneDriveBackup_DiscreteScopes() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
eb := NewOneDriveBackup(test.include)
eb.Include(eb.Users(test.include))
// todo: remove discreteScopes
// eb := NewOneDriveBackup(test.include)
// eb.Include(eb.AllData())
scopes := eb.DiscreteScopes(test.discrete)
for _, sc := range scopes {
users := sc.Get(OneDriveUser)
assert.Equal(t, test.expect, users)
}
// scopes := eb.DiscreteScopes(test.discrete)
// for _, sc := range scopes {
// users := sc.Get(OneDriveUser)
// assert.Equal(t, test.expect, users)
// }
})
}
}
func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Users() {
func (suite *OneDriveSelectorSuite) TestOneDriveSelector_AllData() {
t := suite.T()
const (
u1 = "u1"
u2 = "u2"
)
var (
users = []string{u1, u2}
sel = NewOneDriveBackup(users)
userScopes = sel.Users(users)
users = []string{"u1", "u2"}
sel = NewOneDriveBackup(users)
allScopes = sel.AllData()
)
for _, scope := range userScopes {
// Scope value is either u1 or u2
assert.Contains(t, join(u1, u2), scope[OneDriveUser.String()].Target)
}
assert.ElementsMatch(t, users, sel.DiscreteResourceOwners())
// Initialize the selector Include, Exclude, Filter
sel.Exclude(userScopes)
sel.Include(userScopes)
sel.Filter(userScopes)
sel.Exclude(allScopes)
sel.Include(allScopes)
sel.Filter(allScopes)
table := []struct {
name string
@ -117,14 +110,20 @@ func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Users() {
suite.T().Run(test.name, func(t *testing.T) {
require.Len(t, test.scopesToCheck, 1)
for _, scope := range test.scopesToCheck {
// Scope value is u1,u2
assert.Contains(t, join(u1, u2), scope[OneDriveUser.String()].Target)
scopeMustHave(
t,
OneDriveScope(scope),
map[categorizer]string{
OneDriveItem: AnyTgt,
OneDriveFolder: AnyTgt,
},
)
}
})
}
}
func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Include_Users() {
func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Include_AllData() {
t := suite.T()
const (
@ -133,12 +132,12 @@ func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Include_Users() {
)
var (
users = []string{u1, u2}
sel = NewOneDriveBackup(users)
userScopes = sel.Users(users)
users = []string{u1, u2}
sel = NewOneDriveBackup(users)
allScopes = sel.AllData()
)
sel.Include(userScopes)
sel.Include(allScopes)
scopes := sel.Includes
require.Len(t, scopes, 1)
@ -146,12 +145,15 @@ func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Include_Users() {
scopeMustHave(
t,
OneDriveScope(sc),
map[categorizer]string{OneDriveUser: join(u1, u2)},
map[categorizer]string{
OneDriveItem: AnyTgt,
OneDriveFolder: AnyTgt,
},
)
}
}
func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Exclude_Users() {
func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Exclude_AllData() {
t := suite.T()
const (
@ -160,12 +162,12 @@ func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Exclude_Users() {
)
var (
users = []string{u1, u2}
sel = NewOneDriveBackup(users)
userScopes = sel.Users(users)
users = []string{u1, u2}
sel = NewOneDriveBackup(users)
allScopes = sel.AllData()
)
sel.Exclude(userScopes)
sel.Exclude(allScopes)
scopes := sel.Excludes
require.Len(t, scopes, 1)
@ -173,7 +175,10 @@ func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Exclude_Users() {
scopeMustHave(
t,
OneDriveScope(sc),
map[categorizer]string{OneDriveUser: join(u1, u2)},
map[categorizer]string{
OneDriveItem: AnyTgt,
OneDriveFolder: AnyTgt,
},
)
}
}
@ -248,7 +253,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() {
deets,
func() *OneDriveRestore {
odr := NewOneDriveRestore(Any())
odr.Include(odr.Users(Any()))
odr.Include(odr.AllData())
return odr
},
arr(file, file2, file3),
@ -258,7 +263,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() {
deets,
func() *OneDriveRestore {
odr := NewOneDriveRestore(Any())
odr.Include(odr.Items(Any(), Any(), []string{"file2"}))
odr.Include(odr.Items(Any(), []string{"file2"}))
return odr
},
arr(file2),
@ -268,7 +273,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveRestore_Reduce() {
deets,
func() *OneDriveRestore {
odr := NewOneDriveRestore([]string{"uid"})
odr.Include(odr.Folders([]string{"uid"}, []string{"folderA/folderB", "folderA/folderC"}))
odr.Include(odr.Folders([]string{"folderA/folderB", "folderA/folderC"}))
return odr
},
arr(file, file2),
@ -295,7 +300,6 @@ func (suite *OneDriveSelectorSuite) TestOneDriveCategory_PathValues() {
require.NoError(t, err)
expected := map[categorizer]string{
OneDriveUser: "user",
OneDriveFolder: "dir1/dir2",
OneDriveItem: "file",
}

View File

@ -161,17 +161,16 @@ type (
// makeScope produces a well formatted, typed scope that ensures all base values are populated.
func makeScope[T scopeT](
cat categorizer,
resources, vs []string,
vs []string,
opts ...option,
) T {
sc := &scopeConfig{}
sc.populate(opts...)
s := T{
scopeKeyCategory: filters.Identity(cat.String()),
scopeKeyDataType: filters.Identity(cat.leafCat().String()),
cat.String(): filterize(*sc, vs...),
cat.rootCat().String(): filterize(scopeConfig{}, resources...),
scopeKeyCategory: filters.Identity(cat.String()),
scopeKeyDataType: filters.Identity(cat.leafCat().String()),
cat.String(): filterize(*sc, vs...),
}
return s
@ -326,14 +325,14 @@ func reduce[T scopeT, C categoryT](
continue
}
passed := passes(
dc,
dc.pathValues(repoPath),
*ent,
excls[dc],
filts[dc],
incls[dc],
)
e, f, i := excls[dc], filts[dc], incls[dc]
// at least one filter or inclusion must be presentt
if len(f)+len(i) == 0 {
continue
}
passed := passes(dc, dc.pathValues(repoPath), *ent, e, f, i)
if passed {
ents = append(ents, *ent)
}

View File

@ -98,7 +98,18 @@ type Selector struct {
// A record of the resource owners matched by this selector.
ResourceOwners filters.Filter `json:"resourceOwners,omitempty"`
// The single resource owner used by the selector after splitting.
// The single resource owner being observed by the selector.
// Selectors are constructed by passing in a list of ResourceOwners,
// and those owners represent the "total" data that should be operated
// across all corso operations. But any single operation (backup,restore,
// etc) will only observe a single user at a time, and that user is
// represented by this value.
//
// If the constructor is passed a len=1 list of owners, this value is
// automatically matched to that entry. For lists with more than one
// owner, the user is expected to call SplitByResourceOwner(), and
// iterate over the results, where each one will populate this field
// with a different owner.
DiscreteOwner string `json:"discreteOwner,omitempty"`
// A slice of exclusion scopes. Exclusions apply globally to all
@ -114,7 +125,7 @@ type Selector struct {
// helper for specific selector instance constructors.
func newSelector(s service, resourceOwners []string) Selector {
var owner string
if len(resourceOwners) == 1 {
if len(resourceOwners) == 1 && resourceOwners[0] != AnyTgt {
owner = resourceOwners[0]
}
@ -312,10 +323,11 @@ func selectorAsIface[T any](s Selector) (T, error) {
// ---------------------------------------------------------------------------
type Printable struct {
Service string `json:"service"`
Excludes map[string][]string `json:"excludes,omitempty"`
Filters map[string][]string `json:"filters,omitempty"`
Includes map[string][]string `json:"includes,omitempty"`
ResourceOwners []string `json:"resourceOwners"`
Service string `json:"service"`
Excludes map[string][]string `json:"excludes,omitempty"`
Filters map[string][]string `json:"filters,omitempty"`
Includes map[string][]string `json:"includes,omitempty"`
}
type printabler interface {
@ -335,10 +347,11 @@ func (s Selector) ToPrintable() Printable {
// toPrintable creates the minimized display of a selector, formatted for human readability.
func toPrintable[T scopeT](s Selector) Printable {
return Printable{
Service: s.Service.String(),
Excludes: toResourceTypeMap[T](s.Excludes),
Filters: toResourceTypeMap[T](s.Filters),
Includes: toResourceTypeMap[T](s.Includes),
ResourceOwners: s.DiscreteResourceOwners(),
Service: s.Service.String(),
Excludes: toResourceTypeMap[T](s.Excludes),
Filters: toResourceTypeMap[T](s.Filters),
Includes: toResourceTypeMap[T](s.Includes),
}
}
@ -349,33 +362,30 @@ func toPrintable[T scopeT](s Selector) Printable {
// Resource refers to the top-level entity in the service. User for Exchange,
// Site for sharepoint, etc.
func (p Printable) Resources() string {
s := resourcesShortFormat(p.Includes)
if len(s) == 0 {
s = resourcesShortFormat(p.Filters)
}
s := resourcesShortFormat(p.ResourceOwners)
if len(s) == 0 {
s = "None"
}
if s == AnyTgt {
s = "All"
}
return s
}
// returns a string with the resources in the map. Shortened to the first resource key,
// plus, if more exist, " (len-1 more)"
func resourcesShortFormat(m map[string][]string) string {
var s string
for k := range m {
s = k
break
func resourcesShortFormat(ros []string) string {
switch len(ros) {
case 0:
return ""
case 1:
return ros[0]
default:
return fmt.Sprintf("%s (%d more)", ros[0], len(ros)-1)
}
if len(s) > 0 && len(m) > 1 {
s = fmt.Sprintf("%s (%d more)", s, len(m)-1)
}
return s
}
// Transforms the slice to a single map.

View File

@ -36,11 +36,7 @@ func (suite *SelectorReduceSuite) TestReduce() {
name: "ExchangeAllMail",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.Mails(
selectors.Any(),
selectors.Any(),
selectors.Any(),
))
sel.Include(sel.Mails(selectors.Any(), selectors.Any()))
return sel
},
@ -51,7 +47,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.MailFolders(
selectors.Any(),
[]string{testdata.ExchangeEmailInboxPath.Folder()},
))
@ -75,7 +70,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Filter(sel.MailSender("a-person"))
sel.Exclude(sel.Mails(
selectors.Any(),
selectors.Any(),
[]string{testdata.ExchangeEmailItemPath2.ShortRef()},
))
@ -114,7 +108,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.Mails(
selectors.Any(),
selectors.Any(),
[]string{testdata.ExchangeEmailItemPath1.Item()},
))
@ -128,7 +121,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.Mails(
selectors.Any(),
selectors.Any(),
[]string{testdata.ExchangeEmailItemPath1.ShortRef()},
))
@ -144,7 +136,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
sel.Include(sel.Events(
selectors.Any(),
selectors.Any(),
selectors.Any(),
))
sel.Filter(sel.MailSubject("foo"))
@ -167,9 +158,7 @@ func (suite *SelectorReduceSuite) TestReduce() {
name: "ExchangeAll",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.Users(
selectors.Any(),
))
sel.Include(sel.AllData())
return sel
},
@ -187,7 +176,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.MailFolders(
selectors.Any(),
[]string{testdata.ExchangeEmailBasePath.Folder()},
))
@ -203,7 +191,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.MailFolders(
selectors.Any(),
[]string{testdata.ExchangeEmailBasePath.Folder()},
selectors.PrefixMatch(), // force prefix matching
))
@ -217,7 +204,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.MailFolders(
selectors.Any(),
[]string{testdata.ExchangeEmailInboxPath.Folder()},
))
@ -230,7 +216,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.ContactFolders(
selectors.Any(),
[]string{testdata.ExchangeContactsBasePath.Folder()},
))
@ -243,7 +228,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.ContactFolders(
selectors.Any(),
[]string{testdata.ExchangeContactsRootPath.Folder()},
))
@ -257,7 +241,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.EventCalendars(
selectors.Any(),
[]string{testdata.ExchangeEventsBasePath.Folder()},
))
@ -270,7 +253,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore(selectors.Any())
sel.Include(sel.EventCalendars(
selectors.Any(),
[]string{testdata.ExchangeEventsRootPath.Folder()},
))
@ -282,10 +264,6 @@ func (suite *SelectorReduceSuite) TestReduce() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
test := test
t.Parallel()
output := test.selFunc().Reduce(ctx, allDetails)
assert.ElementsMatch(t, test.expected, output.Entries)
})

View File

@ -71,15 +71,10 @@ func (suite *SelectorSuite) TestPrintable_IncludedResources() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
sel := stubSelector(test.resourceOwners)
p := sel.Printable()
res := p.Resources()
assert.Equal(t, "All", res, "stub starts out as an all-pass")
stubWithResource := func(resource string) scope {
ss := stubScope("")
ss[rootCatStub.String()] = filterize(scopeConfig{}, resource)
return scope(ss)
}
@ -90,11 +85,6 @@ func (suite *SelectorSuite) TestPrintable_IncludedResources() {
sel.Includes = append(sel.Includes, stubWithResource(ro))
sel.Filters = append(sel.Filters, stubWithResource(ro))
}
p = sel.Printable()
res = p.Resources()
assert.True(t, test.expect(res), test.reason)
})
}
}

View File

@ -233,13 +233,13 @@ func (s *SharePointRestore) WebURL(urlSuffixes []string, opts ...option) []Share
// 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]
func (s *sharePoint) Sites(sites []string) []SharePointScope {
func (s *sharePoint) AllData() []SharePointScope {
scopes := []SharePointScope{}
scopes = append(
scopes,
makeScope[SharePointScope](SharePointLibrary, sites, Any()),
makeScope[SharePointScope](SharePointList, sites, Any()),
makeScope[SharePointScope](SharePointLibrary, Any()),
makeScope[SharePointScope](SharePointList, Any()),
)
return scopes
@ -249,13 +249,13 @@ func (s *sharePoint) Sites(sites []string) []SharePointScope {
// 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 {
func (s *sharePoint) Lists(lists []string, opts ...option) []SharePointScope {
var (
scopes = []SharePointScope{}
os = append([]option{pathComparator()}, opts...)
)
scopes = append(scopes, makeScope[SharePointScope](SharePointList, sites, lists, os...))
scopes = append(scopes, makeScope[SharePointScope](SharePointList, lists, os...))
return scopes
}
@ -265,12 +265,12 @@ func (s *sharePoint) Lists(sites, lists []string, opts ...option) []SharePointSc
// 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 {
func (s *sharePoint) ListItems(lists, items []string, opts ...option) []SharePointScope {
scopes := []SharePointScope{}
scopes = append(
scopes,
makeScope[SharePointScope](SharePointListItem, sites, items).
makeScope[SharePointScope](SharePointListItem, items).
set(SharePointList, lists, opts...),
)
@ -281,7 +281,7 @@ func (s *sharePoint) ListItems(sites, lists, items []string, opts ...option) []S
// 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]
func (s *sharePoint) Libraries(sites, libraries []string, opts ...option) []SharePointScope {
func (s *sharePoint) Libraries(libraries []string, opts ...option) []SharePointScope {
var (
scopes = []SharePointScope{}
os = append([]option{pathComparator()}, opts...)
@ -289,7 +289,7 @@ func (s *sharePoint) Libraries(sites, libraries []string, opts ...option) []Shar
scopes = append(
scopes,
makeScope[SharePointScope](SharePointLibrary, sites, libraries, os...),
makeScope[SharePointScope](SharePointLibrary, libraries, os...),
)
return scopes
@ -300,12 +300,12 @@ func (s *sharePoint) Libraries(sites, libraries []string, opts ...option) []Shar
// 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 library scopes.
func (s *sharePoint) LibraryItems(sites, libraries, items []string, opts ...option) []SharePointScope {
func (s *sharePoint) LibraryItems(libraries, items []string, opts ...option) []SharePointScope {
scopes := []SharePointScope{}
scopes = append(
scopes,
makeScope[SharePointScope](SharePointLibraryItem, sites, items).
makeScope[SharePointScope](SharePointLibraryItem, items).
set(SharePointLibrary, libraries, opts...),
)
@ -343,7 +343,7 @@ const (
// sharePointLeafProperties describes common metadata of the leaf categories
var sharePointLeafProperties = map[categorizer]leafProperty{
SharePointLibraryItem: {
pathKeys: []categorizer{SharePointSite, SharePointLibrary, SharePointLibraryItem},
pathKeys: []categorizer{SharePointLibrary, SharePointLibraryItem},
pathType: path.LibrariesCategory,
},
SharePointSite: { // the root category must be represented, even though it isn't a leaf
@ -413,9 +413,8 @@ func (c sharePointCategory) pathValues(p path.Path) map[categorizer]string {
}
return map[categorizer]string{
SharePointSite: p.ResourceOwner(),
folderCat: p.Folder(),
itemCat: p.Item(),
folderCat: p.Folder(),
itemCat: p.Item(),
}
}

View File

@ -67,33 +67,28 @@ func (suite *SharePointSelectorSuite) TestSharePointBackup_DiscreteScopes() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
eb := NewSharePointBackup(test.include)
eb.Include(eb.Sites(test.include))
// todo: remove discreteScopes
// eb := NewSharePointBackup(test.include)
// eb.Include(eb.AllData())
scopes := eb.DiscreteScopes(test.discrete)
for _, sc := range scopes {
sites := sc.Get(SharePointSite)
assert.Equal(t, test.expect, sites)
}
// scopes := eb.DiscreteScopes(test.discrete)
// for _, sc := range scopes {
// sites := sc.Get(SharePointSite)
// assert.Equal(t, test.expect, sites)
// }
})
}
}
func (suite *SharePointSelectorSuite) TestSharePointSelector_Sites() {
func (suite *SharePointSelectorSuite) TestSharePointSelector_AllData() {
t := suite.T()
const (
s1 = "s1"
s2 = "s2"
)
sites := []string{"s1", "s2"}
sel := NewSharePointBackup([]string{s1, s2})
siteScopes := sel.Sites([]string{s1, s2})
sel := NewSharePointBackup(sites)
siteScopes := sel.AllData()
for _, scope := range siteScopes {
// Scope value is either s1 or s2
assert.Contains(t, join(s1, s2), scope[SharePointSite.String()].Target)
}
assert.ElementsMatch(t, sites, sel.DiscreteResourceOwners())
// Initialize the selector Include, Exclude, Filter
sel.Exclude(siteScopes)
@ -109,13 +104,37 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Sites() {
{"Filter Scopes", sel.Filters},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
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)
}
})
require.Len(t, test.scopesToCheck, 2)
for _, scope := range test.scopesToCheck {
var (
spsc = SharePointScope(scope)
cat = spsc.Category()
)
suite.T().Run(test.name+"-"+cat.String(), func(t *testing.T) {
switch cat {
case SharePointLibraryItem:
scopeMustHave(
t,
spsc,
map[categorizer]string{
SharePointLibraryItem: AnyTgt,
SharePointLibrary: AnyTgt,
},
)
case SharePointListItem:
scopeMustHave(
t,
spsc,
map[categorizer]string{
SharePointListItem: AnyTgt,
SharePointList: AnyTgt,
},
)
}
})
}
}
}
@ -198,52 +217,6 @@ 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()
const (
s1 = "s1"
s2 = "s2"
)
sel := NewSharePointBackup([]string{s1, s2})
sel.Include(sel.Sites([]string{s1, s2}))
scopes := sel.Includes
require.Len(t, scopes, 2)
for _, sc := range scopes {
scopeMustHave(
t,
SharePointScope(sc),
map[categorizer]string{SharePointSite: join(s1, s2)},
)
}
}
func (suite *SharePointSelectorSuite) TestSharePointSelector_Exclude_Sites() {
t := suite.T()
const (
s1 = "s1"
s2 = "s2"
)
sel := NewSharePointBackup([]string{s1, s2})
sel.Exclude(sel.Sites([]string{s1, s2}))
scopes := sel.Excludes
require.Len(t, scopes, 2)
for _, sc := range scopes {
scopeMustHave(
t,
SharePointScope(sc),
map[categorizer]string{SharePointSite: join(s1, s2)},
)
}
}
func (suite *SharePointSelectorSuite) TestNewSharePointRestore() {
t := suite.T()
or := NewSharePointRestore(nil)
@ -314,7 +287,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
deets: deets,
makeSelector: func() *SharePointRestore {
odr := NewSharePointRestore(Any())
odr.Include(odr.Sites(Any()))
odr.Include(odr.AllData())
return odr
},
expect: arr(item, item2, item3),
@ -324,7 +297,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
deets: deets,
makeSelector: func() *SharePointRestore {
odr := NewSharePointRestore(Any())
odr.Include(odr.LibraryItems(Any(), Any(), []string{"item2"}))
odr.Include(odr.LibraryItems(Any(), []string{"item2"}))
return odr
},
expect: arr(item2),
@ -334,7 +307,7 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
deets: deets,
makeSelector: func() *SharePointRestore {
odr := NewSharePointRestore([]string{"sid"})
odr.Include(odr.Libraries([]string{"sid"}, []string{"folderA/folderB", "folderA/folderC"}))
odr.Include(odr.Libraries([]string{"folderA/folderB", "folderA/folderC"}))
return odr
},
expect: arr(item, item2),
@ -354,10 +327,8 @@ func (suite *SharePointSelectorSuite) TestSharePointRestore_Reduce() {
}
func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
t := suite.T()
pathBuilder := path.Builder{}.Append("dir1", "dir2", "item")
ten := "tenant"
site := "site"
table := []struct {
name string
sc sharePointCategory
@ -367,7 +338,6 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
name: "SharePoint Libraries",
sc: SharePointLibraryItem,
expected: map[categorizer]string{
SharePointSite: site,
SharePointLibrary: "dir1/dir2",
SharePointLibraryItem: "item",
},
@ -376,7 +346,6 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
name: "SharePoint Lists",
sc: SharePointListItem,
expected: map[categorizer]string{
SharePointSite: site,
SharePointList: "dir1/dir2",
SharePointListItem: "item",
},
@ -384,10 +353,10 @@ func (suite *SharePointSelectorSuite) TestSharePointCategory_PathValues() {
}
for _, test := range table {
t.Run(test.name, func(t *testing.T) {
suite.T().Run(test.name, func(t *testing.T) {
itemPath, err := pathBuilder.ToDataLayerSharePointPath(
ten,
site,
"tenant",
"site",
test.sc.PathType(),
true,
)