corso/src/pkg/selectors/scopes_test.go
Keepers 1f26339813
Match resource owners at top of reduce (#1891)
## Description

Checks for resource owner matches in the top
of the reduce func using the selector owners,
instead of waiting until the path match check.

## 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
2023-01-05 00:59:16 +00:00

550 lines
12 KiB
Go

package selectors
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/filters"
"github.com/alcionai/corso/src/pkg/path"
)
// ---------------------------------------------------------------------------
// tests
// ---------------------------------------------------------------------------
type SelectorScopesSuite struct {
suite.Suite
}
func TestSelectorScopesSuite(t *testing.T) {
suite.Run(t, new(SelectorScopesSuite))
}
func (suite *SelectorScopesSuite) TestContains() {
table := []struct {
name string
scope func() mockScope
check string
expect assert.BoolAssertionFunc
}{
{
name: "any",
scope: func() mockScope {
stub := stubScope("")
return stub
},
check: rootCatStub.String(),
expect: assert.True,
},
{
name: "none",
scope: func() mockScope {
stub := stubScope("")
stub[rootCatStub.String()] = failAny
return stub
},
check: rootCatStub.String(),
expect: assert.False,
},
{
name: "blank value",
scope: func() mockScope {
stub := stubScope("")
stub[rootCatStub.String()] = filters.Equal("")
return stub
},
check: rootCatStub.String(),
expect: assert.False,
},
{
name: "blank target",
scope: func() mockScope {
stub := stubScope("")
stub[rootCatStub.String()] = filterize(scopeConfig{}, "fnords")
return stub
},
check: "",
expect: assert.False,
},
{
name: "matching target",
scope: func() mockScope {
stub := stubScope("")
stub[rootCatStub.String()] = filterize(scopeConfig{}, rootCatStub.String())
return stub
},
check: rootCatStub.String(),
expect: assert.True,
},
{
name: "non-matching target",
scope: func() mockScope {
stub := stubScope("")
stub[rootCatStub.String()] = filterize(scopeConfig{}, rootCatStub.String())
return stub
},
check: "smarf",
expect: assert.False,
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
test.expect(
t,
matches(test.scope(), rootCatStub, test.check))
})
}
}
func (suite *SelectorScopesSuite) TestGetCatValue() {
t := suite.T()
stub := stubScope("")
stub[rootCatStub.String()] = filterize(scopeConfig{}, rootCatStub.String())
assert.Equal(t,
[]string{rootCatStub.String()},
getCatValue(stub, rootCatStub))
assert.Equal(t,
None(),
getCatValue(stub, mockCategorizer("foo")))
}
func (suite *SelectorScopesSuite) TestIsAnyTarget() {
t := suite.T()
stub := stubScope("")
assert.True(t, isAnyTarget(stub, rootCatStub))
assert.True(t, isAnyTarget(stub, leafCatStub))
assert.False(t, isAnyTarget(stub, mockCategorizer("smarf")))
stub = stubScope("none")
assert.False(t, isAnyTarget(stub, rootCatStub))
assert.False(t, isAnyTarget(stub, leafCatStub))
assert.False(t, isAnyTarget(stub, mockCategorizer("smarf")))
}
var reduceTestTable = []struct {
name string
sel func() mockSel
expectLen int
expectPassesReduce assert.BoolAssertionFunc
expectPasses assert.BoolAssertionFunc
}{
{
name: "include all resource owners",
sel: func() mockSel {
sel := stubSelector(Any())
sel.Filters = nil
sel.Excludes = nil
return sel
},
expectLen: 1,
expectPasses: assert.True,
},
{
name: "include all scopes",
sel: func() mockSel {
sel := stubSelector(Any())
sel.Filters = nil
sel.Excludes = nil
return sel
},
expectLen: 1,
expectPasses: assert.True,
},
{
name: "include none resource owners",
sel: func() mockSel {
sel := stubSelector(None())
sel.Includes[0] = scope(stubScope(AnyTgt))
sel.Filters = nil
sel.Excludes = nil
return sel
},
expectLen: 0,
expectPasses: assert.True, // passes() does not check owners
},
{
name: "include none scopes",
sel: func() mockSel {
sel := stubSelector(Any())
sel.Includes[0] = scope(stubScope("none"))
sel.Filters = nil
sel.Excludes = nil
return sel
},
expectLen: 0,
expectPasses: assert.False,
},
{
name: "filter and include all",
sel: func() mockSel {
sel := stubSelector(Any())
sel.Excludes = nil
return sel
},
expectLen: 1,
expectPasses: assert.True,
},
{
name: "include all filter none",
sel: func() mockSel {
sel := stubSelector(Any())
sel.Filters[0] = scope(stubInfoScope("none"))
sel.Excludes = nil
return sel
},
expectLen: 0,
expectPasses: assert.False,
},
{
name: "include all exclude all",
sel: func() mockSel {
sel := stubSelector(Any())
sel.Filters = nil
return sel
},
expectLen: 0,
expectPasses: assert.False,
},
{
name: "include all exclude none",
sel: func() mockSel {
sel := stubSelector(Any())
sel.Filters = nil
sel.Excludes[0] = scope(stubScope("none"))
return sel
},
expectLen: 1,
expectPasses: assert.True,
},
{
name: "filter all exclude all",
sel: func() mockSel {
sel := stubSelector(Any())
sel.Includes = nil
return sel
},
expectLen: 0,
expectPasses: assert.False,
},
{
name: "filter all exclude none",
sel: func() mockSel {
sel := stubSelector(Any())
sel.Includes = nil
sel.Excludes[0] = scope(stubScope("none"))
return sel
},
expectLen: 1,
expectPasses: assert.True,
},
}
func (suite *SelectorScopesSuite) TestReduce() {
deets := func() details.Details {
return details.Details{
DetailsModel: details.DetailsModel{
Entries: []details.DetailsEntry{
{
RepoRef: stubRepoRef(
pathServiceStub,
pathCatStub,
rootCatStub.String(),
"stub",
leafCatStub.String(),
),
},
},
},
}
}
dataCats := map[path.CategoryType]mockCategorizer{
pathCatStub: rootCatStub,
}
for _, test := range reduceTestTable {
suite.T().Run(test.name, func(t *testing.T) {
ctx, flush := tester.NewContext()
defer flush()
ds := deets()
result := reduce[mockScope](
ctx,
&ds,
test.sel().Selector,
dataCats)
require.NotNil(t, result)
assert.Len(t, result.Entries, test.expectLen)
})
}
}
func (suite *SelectorScopesSuite) TestScopesByCategory() {
t := suite.T()
s1 := stubScope("")
s2 := stubScope("")
s2[scopeKeyCategory] = filterize(scopeConfig{}, unknownCatStub.String())
result := scopesByCategory[mockScope](
[]scope{scope(s1), scope(s2)},
map[path.CategoryType]mockCategorizer{
path.UnknownCategory: rootCatStub,
},
false)
assert.Len(t, result, 1)
assert.Len(t, result[rootCatStub], 2)
assert.Empty(t, result[leafCatStub])
}
func (suite *SelectorScopesSuite) TestPasses() {
cat := rootCatStub
pth := stubPath(suite.T(), "uid", []string{"fld"}, path.EventsCategory)
pathVals := cat.pathValues(pth)
entry := details.DetailsEntry{}
for _, test := range reduceTestTable {
suite.T().Run(test.name, func(t *testing.T) {
sel := test.sel()
excl := toMockScope(sel.Excludes)
filt := toMockScope(sel.Filters)
incl := toMockScope(sel.Includes)
result := passes(
cat,
pathVals,
entry,
excl, filt, incl)
test.expectPasses(t, result)
})
}
}
func toMockScope(sc []scope) []mockScope {
if len(sc) == 0 {
return nil
}
ms := []mockScope{}
for _, s := range sc {
ms = append(ms, mockScope(s))
}
return ms
}
func (suite *SelectorScopesSuite) TestMatchesPathValues() {
cat := rootCatStub
pvs := stubPathValues()
short := "brunheelda"
table := []struct {
name string
cat mockCategorizer
rootVal string
leafVal string
shortRef string
expect assert.BoolAssertionFunc
}{
{
name: "matching values",
rootVal: rootCatStub.String(),
leafVal: leafCatStub.String(),
expect: assert.True,
},
{
name: "any",
rootVal: AnyTgt,
leafVal: AnyTgt,
expect: assert.True,
},
{
name: "none",
rootVal: NoneTgt,
leafVal: NoneTgt,
expect: assert.False,
},
{
name: "mismatched values",
rootVal: "fnords",
leafVal: "smarf",
expect: assert.False,
},
{
name: "leaf matches shortRef",
rootVal: rootCatStub.String(),
leafVal: short,
shortRef: short,
expect: assert.True,
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
sc := stubScope("")
sc[rootCatStub.String()] = filterize(scopeConfig{}, test.rootVal)
sc[leafCatStub.String()] = filterize(scopeConfig{}, test.leafVal)
test.expect(t, matchesPathValues(sc, cat, pvs, test.shortRef))
})
}
}
func (suite *SelectorScopesSuite) TestAddToSet() {
t := suite.T()
set := []string{}
set = addToSet(set, []string{})
assert.Len(t, set, 0)
set = addToSet(set, []string{"a"})
assert.Len(t, set, 1)
assert.Equal(t, set[0], "a")
set = addToSet(set, []string{"a"})
assert.Len(t, set, 1)
set = addToSet(set, []string{"a", "b"})
assert.Len(t, set, 2)
assert.Equal(t, set[0], "a")
assert.Equal(t, set[1], "b")
set = addToSet(set, []string{"c", "d"})
assert.Len(t, set, 4)
assert.Equal(t, set[0], "a")
assert.Equal(t, set[1], "b")
assert.Equal(t, set[2], "c")
assert.Equal(t, set[3], "d")
}
func (suite *SelectorScopesSuite) TestClean() {
table := []struct {
name string
input []string
expect []string
}{
{
name: "nil",
input: nil,
expect: None(),
},
{
name: "has anyTgt",
input: []string{"a", AnyTgt},
expect: Any(),
},
{
name: "has noneTgt",
input: []string{"a", NoneTgt},
expect: None(),
},
{
name: "has anyTgt and noneTgt, any first",
input: []string{"a", AnyTgt, NoneTgt},
expect: Any(),
},
{
name: "has noneTgt and anyTgt, none first",
input: []string{"a", NoneTgt, AnyTgt},
expect: None(),
},
{
name: "already clean",
input: []string{"a", "b"},
expect: []string{"a", "b"},
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
result := clean(test.input)
assert.Equal(t, result, test.expect)
})
}
}
func (suite *SelectorScopesSuite) TestWrapFilter() {
table := []struct {
name string
filter filterFunc
input []string
comparator int
target string
}{
{
name: "any",
filter: filters.Contains,
input: Any(),
comparator: int(filters.Passes),
target: AnyTgt,
},
{
name: "none",
filter: filters.In,
input: None(),
comparator: int(filters.Fails),
target: NoneTgt,
},
{
name: "something",
filter: filters.Equal,
input: []string{"userid"},
comparator: int(filters.EqualTo),
target: "userid",
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
ff := wrapFilter(test.filter)(test.input)
assert.Equal(t, int(ff.Comparator), test.comparator)
assert.Equal(t, ff.Target, test.target)
})
}
}
func (suite *SelectorScopesSuite) TestScopeConfig() {
input := "input"
table := []struct {
name string
config scopeConfig
expect int
}{
{
name: "no configs set",
config: scopeConfig{},
expect: int(filters.EqualTo),
},
{
name: "force prefix",
config: scopeConfig{usePrefixFilter: true},
expect: int(filters.TargetPrefixes),
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
result := filterize(test.config, input)
assert.Equal(t, test.expect, int(result.Comparator))
})
}
}
func (suite *SelectorScopesSuite) TestDiscreteCopy() {
var (
t = suite.T()
orig = stubScope(AnyTgt)
clone = discreteCopy(orig, "fnords")
)
for k, v := range orig {
if k != rootCatStub.String() {
assert.Equal(t, v.Target, clone[k].Target)
} else {
assert.Equal(t, AnyTgt, v.Target)
assert.Equal(t, "fnords", clone[k].Target)
}
}
}