From 2d88e59cd07dc7e9f862281ca764eca6e7f6fe65 Mon Sep 17 00:00:00 2001 From: Keepers Date: Tue, 23 Aug 2022 15:56:24 -0600 Subject: [PATCH] Issue-556 introduce discreteScopes in selector handling (#635) Graph may have an easier time parsing scopes if the root user is discretely identified, as opposed to being a wildcard. DiscreteScopes() automatically handles replacement of scopes matching Any() user with the set of user provided discrete IDs. --- src/pkg/selectors/exchange.go | 7 ++ src/pkg/selectors/exchange_test.go | 103 +++++++++++++++++++++-------- src/pkg/selectors/onedrive.go | 7 ++ src/pkg/selectors/onedrive_test.go | 41 ++++++++++++ src/pkg/selectors/selectors.go | 36 ++++++++++ 5 files changed, 166 insertions(+), 28 deletions(-) diff --git a/src/pkg/selectors/exchange.go b/src/pkg/selectors/exchange.go index caa889fc6..8f4873380 100644 --- a/src/pkg/selectors/exchange.go +++ b/src/pkg/selectors/exchange.go @@ -143,6 +143,13 @@ func (s *exchange) Scopes() []ExchangeScope { return scopes[ExchangeScope](s.Selector) } +// DiscreteScopes retrieves the list of exchangeScopes in the selector. +// If any Include scope's User category is set to Any, replaces that +// scope's value with the list of userIDs instead. +func (s *exchange) DiscreteScopes(userIDs []string) []ExchangeScope { + return discreteScopes[ExchangeScope](s.Selector, ExchangeUser, userIDs) +} + // ------------------- // Scope Factories diff --git a/src/pkg/selectors/exchange_test.go b/src/pkg/selectors/exchange_test.go index 4a6dfff85..62655f838 100644 --- a/src/pkg/selectors/exchange_test.go +++ b/src/pkg/selectors/exchange_test.go @@ -373,27 +373,69 @@ func (suite *ExchangeSourceSuite) TestExchangeDestination_GetOrDefault() { } } -var allScopesExceptUnknown = scope{ - ExchangeContact.String(): AnyTgt, - ExchangeContactFolder.String(): AnyTgt, - ExchangeEvent.String(): AnyTgt, - ExchangeMail.String(): AnyTgt, - ExchangeMailFolder.String(): AnyTgt, - ExchangeUser.String(): AnyTgt, -} - func (suite *ExchangeSourceSuite) TestExchangeBackup_Scopes() { eb := NewExchangeBackup() - eb.Includes = []scope{allScopesExceptUnknown} - // todo: swap the above for this - // eb := NewExchangeBackup().IncludeUsers(AnyTgt) + eb.Include(eb.Users(Any())) scopes := eb.Scopes() - assert.Len(suite.T(), scopes, 1) - assert.Equal( - suite.T(), - allScopesExceptUnknown, - scope(scopes[0])) + assert.Len(suite.T(), scopes, 3) + 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)) + assert.True(t, sc.IsAny(ExchangeContactFolder)) + case ExchangeEvent: + assert.True(t, sc.IsAny(ExchangeEvent)) + case ExchangeMailFolder: + assert.True(t, sc.IsAny(ExchangeMail)) + assert.True(t, sc.IsAny(ExchangeMailFolder)) + } + }) + } +} + +func (suite *ExchangeSourceSuite) TestExchangeBackup_DiscreteScopes() { + usrs := []string{"u1", "u2"} + table := []struct { + name string + include []string + discrete []string + expect []string + }{ + { + name: "any user", + include: Any(), + discrete: usrs, + expect: usrs, + }, + { + name: "discrete user", + include: []string{"u3"}, + discrete: usrs, + expect: []string{"u3"}, + }, + { + name: "nil discrete slice", + include: Any(), + discrete: nil, + expect: Any(), + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + eb := NewExchangeBackup() + eb.Include(eb.Users(test.include)) + + scopes := eb.DiscreteScopes(test.discrete) + for _, sc := range scopes { + users := sc.Get(ExchangeUser) + assert.Equal(t, test.expect, users) + } + }) + } } func (suite *ExchangeSourceSuite) TestExchangeScope_Category() { @@ -461,11 +503,9 @@ func (suite *ExchangeSourceSuite) TestExchangeScope_IncludesCategory() { func (suite *ExchangeSourceSuite) TestExchangeScope_Get() { eb := NewExchangeBackup() - eb.Includes = []scope{allScopesExceptUnknown} - // todo: swap the above for this - // eb := NewExchangeBackup().IncludeUsers(AnyTgt) + eb.Include(eb.Users(Any())) - scope := eb.Scopes()[0] + scopes := eb.Scopes() table := []exchangeCategory{ ExchangeContact, @@ -476,15 +516,22 @@ func (suite *ExchangeSourceSuite) TestExchangeScope_Get() { ExchangeUser, } - assert.Equal( - suite.T(), - None(), - scope.Get(ExchangeCategoryUnknown)) - - expect := Any() for _, test := range table { suite.T().Run(test.String(), func(t *testing.T) { - assert.Equal(t, expect, scope.Get(test)) + for _, sc := range scopes { + assert.Equal(t, Any(), sc.Get(ExchangeUser)) + switch sc.Category() { + case ExchangeContactFolder: + assert.Equal(t, Any(), sc.Get(ExchangeContact)) + assert.Equal(t, Any(), sc.Get(ExchangeContactFolder)) + case ExchangeEvent: + assert.Equal(t, Any(), sc.Get(ExchangeEvent)) + case ExchangeMailFolder: + assert.Equal(t, Any(), sc.Get(ExchangeMail)) + assert.Equal(t, Any(), sc.Get(ExchangeMailFolder)) + } + assert.Equal(t, None(), sc.Get(ExchangeCategoryUnknown)) + } }) } } diff --git a/src/pkg/selectors/onedrive.go b/src/pkg/selectors/onedrive.go index 344ab11b0..311ab6367 100644 --- a/src/pkg/selectors/onedrive.go +++ b/src/pkg/selectors/onedrive.go @@ -121,6 +121,13 @@ func (s *onedrive) Scopes() []OneDriveScope { return scopes[OneDriveScope](s.Selector) } +// DiscreteScopes retrieves the list of onedriveScopes in the selector. +// If any Include scope's User category is set to Any, replaces that +// scope's value with the list of userIDs instead. +func (s *onedrive) DiscreteScopes(userIDs []string) []OneDriveScope { + return discreteScopes[OneDriveScope](s.Selector, OneDriveUser, userIDs) +} + // --------------------------------------------------------------------------- // Categories // --------------------------------------------------------------------------- diff --git a/src/pkg/selectors/onedrive_test.go b/src/pkg/selectors/onedrive_test.go index 1c972b280..225d0e42b 100644 --- a/src/pkg/selectors/onedrive_test.go +++ b/src/pkg/selectors/onedrive_test.go @@ -33,6 +33,47 @@ func (suite *OnedriveSourceSuite) TestToOnedriveBackup() { assert.NotZero(t, ob.Scopes()) } +func (suite *OnedriveSourceSuite) TestOnedriveBackup_DiscreteScopes() { + usrs := []string{"u1", "u2"} + table := []struct { + name string + include []string + discrete []string + expect []string + }{ + { + name: "any user", + include: Any(), + discrete: usrs, + expect: usrs, + }, + { + name: "discrete user", + include: []string{"u3"}, + discrete: usrs, + expect: []string{"u3"}, + }, + { + name: "nil discrete slice", + include: Any(), + discrete: nil, + expect: Any(), + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + eb := NewOneDriveBackup() + eb.Include(eb.Users(test.include)) + + scopes := eb.DiscreteScopes(test.discrete) + for _, sc := range scopes { + users := sc.Get(OneDriveUser) + assert.Equal(t, test.expect, users) + } + }) + } +} + func (suite *OnedriveSourceSuite) TestOnedriveSelector_Users() { t := suite.T() sel := NewOneDriveBackup() diff --git a/src/pkg/selectors/selectors.go b/src/pkg/selectors/selectors.go index 97327adfe..7360bab58 100644 --- a/src/pkg/selectors/selectors.go +++ b/src/pkg/selectors/selectors.go @@ -132,6 +132,42 @@ func scopes[T scopeT](s Selector) []T { return scopes } +// discreteScopes retrieves the list of scopes in the selector. +// for any scope in the `Includes` set, if scope.IsAny(rootCat), +// then that category's value is replaced with the provided set of +// discrete identifiers. +// If discreteIDs is an empty slice, returns the normal scopes(s). +// future TODO: if Includes is nil, return filters. +func discreteScopes[T scopeT, C categoryT]( + s Selector, + rootCat C, + discreteIDs []string, +) []T { + sl := []T{} + jdid := join(discreteIDs...) + + if len(jdid) == 0 { + return scopes[T](s) + } + + for _, v := range s.Includes { + t := T(v) + + if isAnyTarget(t, rootCat) { + w := T{} + for k, v := range t { + w[k] = v + } + set(w, rootCat, jdid) + t = w + + } + sl = append(sl, t) + } + + return sl +} + // --------------------------------------------------------------------------- // Printing Selectors for Human Reading // ---------------------------------------------------------------------------