utilize shorthash in selector sels (#854)

## Description

The details entry shorthash can be treated as
equal to the leaf item ID.  This adds support to
the selector reduce step to compare the leaf val
to either the path item ID or the shortHash.

## Type of change

- [x] 🌻 Feature

## Issue(s)

* closes #572

## Test Plan

- [ ] 💪 Manual
- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2022-09-15 10:53:03 -06:00 committed by GitHub
parent a368570e20
commit ed52a07e2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 32 deletions

View File

@ -551,6 +551,11 @@ func (ec exchangeCategory) unknownCat() categorizer {
return ExchangeCategoryUnknown
}
// isLeaf is true if the category is a mail, event, or contact category.
func (ec exchangeCategory) isLeaf() bool {
return ec == ec.leafCat()
}
// pathValues transforms a path to a map of identified properties.
//
// Example:
@ -692,7 +697,7 @@ func (s ExchangeScope) matchesEntry(
entry details.DetailsEntry,
) bool {
// matchesPathValues can be handled generically, thanks to SCIENCE.
return matchesPathValues(s, cat.(exchangeCategory), pathValues) || s.matchesInfo(entry.Exchange)
return matchesPathValues(s, cat.(exchangeCategory), pathValues, entry.ShortRef) || s.matchesInfo(entry.Exchange)
}
// matchesInfo handles the standard behavior when comparing a scope and an ExchangeFilter

View File

@ -779,30 +779,34 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesPath() {
)
var (
pth = stubPath(suite.T(), usr, []string{fld, mail}, path.EmailCategory)
es = NewExchangeRestore()
pth = stubPath(suite.T(), usr, []string{fld, mail}, path.EmailCategory)
short = "thisisahashofsomekind"
es = NewExchangeRestore()
)
table := []struct {
name string
scope []ExchangeScope
expect assert.BoolAssertionFunc
name string
scope []ExchangeScope
shortRef string
expect assert.BoolAssertionFunc
}{
{"all user's items", es.Users(Any()), assert.True},
{"no user's items", es.Users(None()), assert.False},
{"matching user", es.Users([]string{usr}), assert.True},
{"non-matching user", es.Users([]string{"smarf"}), assert.False},
{"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{fld}), assert.True},
{"non-matching folder", es.MailFolders(Any(), []string{"smarf"}), assert.False},
{"one of multiple folders", es.MailFolders(Any(), []string{"smarf", fld}), 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},
{"all user's items", es.Users(Any()), "", assert.True},
{"no user's items", es.Users(None()), "", assert.False},
{"matching user", es.Users([]string{usr}), "", assert.True},
{"non-matching user", es.Users([]string{"smarf"}), "", assert.False},
{"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{fld}), "", assert.True},
{"non-matching folder", es.MailFolders(Any(), []string{"smarf"}), "", assert.False},
{"one of multiple folders", es.MailFolders(Any(), []string{"smarf", fld}), "", 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},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
@ -810,7 +814,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesPath() {
var aMatch bool
for _, scope := range scopes {
pv := ExchangeMail.pathValues(pth)
if matchesPathValues(scope, ExchangeMail, pv) {
if matchesPathValues(scope, ExchangeMail, pv, short) {
aMatch = true
break
}
@ -1072,7 +1076,8 @@ func (suite *ExchangeSelectorSuite) TestScopesByCategory() {
}
func (suite *ExchangeSelectorSuite) TestPasses() {
deets := details.DetailsEntry{}
short := "thisisahashofsomekind"
entry := details.DetailsEntry{ShortRef: short}
const (
mid = "mailID"
@ -1118,7 +1123,7 @@ func (suite *ExchangeSelectorSuite) TestPasses() {
result := passes(
cat,
cat.pathValues(pth),
deets,
entry,
test.excludes,
test.filters,
test.includes)

View File

@ -47,6 +47,10 @@ func (mc mockCategorizer) unknownCat() categorizer {
return unknownCatStub
}
func (mc mockCategorizer) isLeaf() bool {
return mc == leafCatStub
}
func (mc mockCategorizer) pathValues(pth path.Path) map[categorizer]string {
return map[categorizer]string{rootCatStub: "stub"}
}

View File

@ -183,6 +183,11 @@ func (c oneDriveCategory) unknownCat() categorizer {
return OneDriveCategoryUnknown
}
// isLeaf is true if the category is a mail, event, or contact category.
func (c oneDriveCategory) isLeaf() bool {
return c == c.leafCat()
}
// pathValues transforms a path to a map of identified properties.
//
// Example:
@ -271,7 +276,7 @@ func (s OneDriveScope) matchesEntry(
entry details.DetailsEntry,
) bool {
// matchesPathValues can be handled generically, thanks to SCIENCE.
return matchesPathValues(s, cat.(oneDriveCategory), pathValues) || s.matchesInfo(entry.OneDrive)
return matchesPathValues(s, cat.(oneDriveCategory), pathValues, entry.ShortRef) || s.matchesInfo(entry.OneDrive)
}
// matchesInfo handles the standard behavior when comparing a scope and an oneDriveInfo

View File

@ -32,6 +32,10 @@ type (
// unknownType returns the unknown category value
unknownCat() categorizer
// isLeaf returns true if the category is one of the leaf categories.
// eg: in a resourceOwner/folder/item structure, the item is the leaf.
isLeaf() bool
// pathValues should produce a map of category:string pairs populated by extracting
// values out of the path.Path struct.
//
@ -205,7 +209,6 @@ func isAnyTarget[T scopeT, C categoryT](s T, cat C) bool {
// reduce filters the entries in the details to only those that match the
// inclusions, filters, and exclusions in the selector.
//
func reduce[T scopeT, C categoryT](
ctx context.Context,
deets *details.Details,
@ -337,6 +340,7 @@ func matchesPathValues[T scopeT, C categoryT](
sc T,
cat C,
pathValues map[categorizer]string,
shortRef string,
) bool {
// if scope specifies a filter category,
// path checking is automatically skipped.
@ -362,7 +366,12 @@ func matchesPathValues[T scopeT, C categoryT](
// all parts of the scope must match
cc := c.(C)
if !isAnyTarget(sc, cc) {
if filters.NotContains(join(scopeVals...)).Compare(pathVal) {
notMatch := filters.NotContains(join(scopeVals...))
if c.isLeaf() && len(shortRef) > 0 {
if notMatch.Compare(pathVal) && notMatch.Compare(shortRef) {
return false
}
} else if notMatch.Compare(pathVal) {
return false
}
}

View File

@ -301,12 +301,15 @@ func toMockScope(sc []scope) []mockScope {
func (suite *SelectorScopesSuite) TestMatchesPathValues() {
cat := rootCatStub
pvs := stubPathValues()
short := "brunheelda"
table := []struct {
name string
rootVal string
leafVal string
expect assert.BoolAssertionFunc
name string
cat mockCategorizer
rootVal string
leafVal string
shortRef string
expect assert.BoolAssertionFunc
}{
{
name: "matching values",
@ -332,6 +335,20 @@ func (suite *SelectorScopesSuite) TestMatchesPathValues() {
leafVal: "smarf",
expect: assert.False,
},
{
name: "leaf matches shortRef",
rootVal: rootCatStub.String(),
leafVal: short,
shortRef: short,
expect: assert.True,
},
{
name: "root matches shortRef",
rootVal: short,
leafVal: leafCatStub.String(),
shortRef: short,
expect: assert.False,
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
@ -339,7 +356,7 @@ func (suite *SelectorScopesSuite) TestMatchesPathValues() {
sc[rootCatStub.String()] = filterize(test.rootVal)
sc[leafCatStub.String()] = filterize(test.leafVal)
test.expect(t, matchesPathValues(sc, cat, pvs))
test.expect(t, matchesPathValues(sc, cat, pvs, test.shortRef))
})
}
}