clean out scope value chaff (#731)

This commit is contained in:
Keepers 2022-09-09 19:21:31 -06:00 committed by GitHub
parent 25ce11b2c6
commit a226035c23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 116 additions and 115 deletions

View File

@ -92,7 +92,7 @@ func (b Backup) MinimumPrintable() any {
StartedAt: b.StartedAt,
Status: b.Status,
Version: "0",
Selectors: b.Selectors.Printable(),
Selectors: b.Selectors.ToPrintable(),
}
}
@ -117,6 +117,6 @@ func (b Backup) Values() []string {
common.FormatTime(b.StartedAt),
string(b.ID),
status,
b.Selectors.Printable().Resources(),
b.Selectors.ToPrintable().Resources(),
}
}

View File

@ -90,7 +90,7 @@ func (suite *BackupSuite) TestBackup_MinimumPrintable() {
assert.Equal(t, now, result.StartedAt, "started at")
assert.Equal(t, b.Status, result.Status, "status")
bselp := b.Selectors.Printable()
bselp := b.Selectors.ToPrintable()
assert.Equal(t, bselp, result.Selectors, "selectors")
assert.Equal(t, bselp.Resources(), result.Selectors.Resources(), "selector resources")
}

View File

@ -80,6 +80,11 @@ func (s Selector) ToExchangeRestore() (*ExchangeRestore, error) {
return &src, nil
}
// Printable creates the minimized display of a selector, formatted for human readability.
func (s exchange) Printable() Printable {
return toPrintable[ExchangeScope](s.Selector)
}
// -------------------
// Exclude/Includes
@ -169,7 +174,7 @@ func (s *exchange) Contacts(users, folders, contacts []string) []ExchangeScope {
scopes = append(
scopes,
makeScope[ExchangeScope](Item, ExchangeContact, users, contacts).
makeScope[ExchangeScope](ExchangeContact, users, contacts).
set(ExchangeContactFolder, folders),
)
@ -185,7 +190,7 @@ func (s *exchange) ContactFolders(users, folders []string) []ExchangeScope {
scopes = append(
scopes,
makeScope[ExchangeScope](Group, ExchangeContactFolder, users, folders),
makeScope[ExchangeScope](ExchangeContactFolder, users, folders),
)
return scopes
@ -200,7 +205,7 @@ func (s *exchange) Events(users, calendars, events []string) []ExchangeScope {
scopes = append(
scopes,
makeScope[ExchangeScope](Item, ExchangeEvent, users, events).
makeScope[ExchangeScope](ExchangeEvent, users, events).
set(ExchangeEventCalendar, calendars),
)
@ -217,7 +222,7 @@ func (s *exchange) EventCalendars(users, events []string) []ExchangeScope {
scopes = append(
scopes,
makeScope[ExchangeScope](Group, ExchangeEventCalendar, users, events),
makeScope[ExchangeScope](ExchangeEventCalendar, users, events),
)
return scopes
@ -232,7 +237,7 @@ func (s *exchange) Mails(users, folders, mails []string) []ExchangeScope {
scopes = append(
scopes,
makeScope[ExchangeScope](Item, ExchangeMail, users, mails).
makeScope[ExchangeScope](ExchangeMail, users, mails).
set(ExchangeMailFolder, folders),
)
@ -248,7 +253,7 @@ func (s *exchange) MailFolders(users, folders []string) []ExchangeScope {
scopes = append(
scopes,
makeScope[ExchangeScope](Group, ExchangeMailFolder, users, folders),
makeScope[ExchangeScope](ExchangeMailFolder, users, folders),
)
return scopes
@ -263,9 +268,9 @@ func (s *exchange) Users(users []string) []ExchangeScope {
scopes := []ExchangeScope{}
scopes = append(scopes,
makeScope[ExchangeScope](Group, ExchangeContactFolder, users, Any()),
makeScope[ExchangeScope](Item, ExchangeEventCalendar, users, Any()),
makeScope[ExchangeScope](Group, ExchangeMailFolder, users, Any()),
makeScope[ExchangeScope](ExchangeContactFolder, users, Any()),
makeScope[ExchangeScope](ExchangeEventCalendar, users, Any()),
makeScope[ExchangeScope](ExchangeMailFolder, users, Any()),
)
return scopes
@ -618,12 +623,6 @@ func (s ExchangeScope) FilterCategory() exchangeCategory {
return exchangeCategory(getFilterCategory(s))
}
// Granularity describes the granularity (directory || item)
// of the data in scope.
func (s ExchangeScope) Granularity() string {
return getGranularity(s)
}
// IncludeCategory checks whether the scope includes a certain category of data.
// Ex: to check if the scope includes mail data:
// s.IncludesCategory(selector.ExchangeMail)

View File

@ -89,7 +89,6 @@ func (ms mockScope) setDefaults() {}
const (
shouldMatch = "should-match-entry"
stubResource = "stubResource"
)
// helper funcs
@ -102,8 +101,6 @@ func stubScope(match string) mockScope {
return mockScope{
rootCatStub.String(): passAny,
scopeKeyCategory: filters.Identity(rootCatStub.String()),
scopeKeyGranularity: filters.Identity(Item),
scopeKeyResource: filters.Identity(stubResource),
scopeKeyDataType: filters.Identity(rootCatStub.String()),
shouldMatch: filters.Identity(sm),
}
@ -113,15 +110,25 @@ func stubScope(match string) mockScope {
// selectors
// ---------------------------------------------------------------------------
func stubSelector() Selector {
return Selector{
type mockSel struct {
Selector
}
func stubSelector() mockSel {
return mockSel{
Selector: Selector{
Service: ServiceExchange,
Excludes: []scope{scope(stubScope(""))},
Filters: []scope{scope(stubScope(""))},
Includes: []scope{scope(stubScope(""))},
},
}
}
func (s mockSel) Printable() Printable {
return toPrintable[mockScope](s.Selector)
}
// ---------------------------------------------------------------------------
// helper funcs
// ---------------------------------------------------------------------------

View File

@ -46,6 +46,11 @@ func (s Selector) ToOneDriveBackup() (*OneDriveBackup, error) {
return &src, nil
}
// Printable creates the minimized display of a selector, formatted for human readability.
func (s oneDrive) Printable() Printable {
return toPrintable[OneDriveScope](s.Selector)
}
// -------------------
// Scope Factories
@ -113,7 +118,7 @@ func (s *oneDrive) Filter(scopes ...[]OneDriveScope) {
func (s *oneDrive) Users(users []string) []OneDriveScope {
scopes := []OneDriveScope{}
scopes = append(scopes, makeScope[OneDriveScope](Group, OneDriveUser, users, users))
scopes = append(scopes, makeScope[OneDriveScope](OneDriveUser, users, users))
return scopes
}
@ -238,12 +243,6 @@ func (s OneDriveScope) FilterCategory() oneDriveCategory {
return oneDriveCategory(getFilterCategory(s))
}
// Granularity describes the granularity (directory || item)
// of the data in scope.
func (s OneDriveScope) Granularity() string {
return getGranularity(s)
}
// IncludeCategory checks whether the scope includes a
// certain category of data.
// Ex: to check if the scope includes file data:

View File

@ -117,15 +117,12 @@ type (
// makeScope produces a well formatted, typed scope that ensures all base values are populated.
func makeScope[T scopeT](
granularity string,
cat categorizer,
resources, vs []string,
) T {
s := T{
scopeKeyCategory: filters.Identity(cat.String()),
scopeKeyDataType: filters.Identity(cat.leafCat().String()),
scopeKeyGranularity: filters.Identity(granularity),
scopeKeyResource: filters.Identity(join(resources...)),
cat.String(): filterize(vs...),
cat.rootCat().String(): filterize(resources...),
}
@ -143,9 +140,7 @@ func makeFilterScope[T scopeT](
return T{
scopeKeyCategory: filters.Identity(cat.String()),
scopeKeyDataType: filters.Identity(cat.leafCat().String()),
scopeKeyGranularity: filters.Identity(Filter),
scopeKeyInfoFilter: filters.Identity(filterCat.String()),
scopeKeyResource: filters.Identity(Filter),
filterCat.String(): f(clean(vs)),
}
}
@ -179,11 +174,6 @@ func getFilterCategory[T scopeT](s T) string {
return s[scopeKeyInfoFilter].Target
}
// getGranularity returns the scope's granularity value.
func getGranularity[T scopeT](s T) string {
return s[scopeKeyGranularity].Target
}
// getCatValue takes the value of s[cat], split it by the standard
// delimiter, and returns the slice. If s[cat] is nil, returns
// None().
@ -203,12 +193,6 @@ func set[T scopeT](s T, cat categorizer, v []string) T {
return s
}
// granularity describes the granularity (directory || item)
// of the data in scope.
func granularity[T scopeT](s T) string {
return s[scopeKeyGranularity].Target
}
// returns true if the category is included in the scope's category type,
// and the value is set to Any().
func isAnyTarget[T scopeT, C categoryT](s T, cat C) bool {

View File

@ -110,12 +110,6 @@ func (suite *SelectorScopesSuite) TestGetCatValue() {
assert.Equal(t, None(), getCatValue(stub, leafCatStub))
}
func (suite *SelectorScopesSuite) TestGranularity() {
t := suite.T()
stub := stubScope("")
assert.Equal(t, Item, granularity(stub))
}
func (suite *SelectorScopesSuite) TestIsAnyTarget() {
t := suite.T()
stub := stubScope("")
@ -125,13 +119,13 @@ func (suite *SelectorScopesSuite) TestIsAnyTarget() {
var reduceTestTable = []struct {
name string
sel func() Selector
sel func() mockSel
expectLen int
expectPasses assert.BoolAssertionFunc
}{
{
name: "include all",
sel: func() Selector {
sel: func() mockSel {
sel := stubSelector()
sel.Filters = nil
sel.Excludes = nil
@ -142,7 +136,7 @@ var reduceTestTable = []struct {
},
{
name: "include none",
sel: func() Selector {
sel: func() mockSel {
sel := stubSelector()
sel.Includes[0] = scope(stubScope("none"))
sel.Filters = nil
@ -154,7 +148,7 @@ var reduceTestTable = []struct {
},
{
name: "filter and include all",
sel: func() Selector {
sel: func() mockSel {
sel := stubSelector()
sel.Excludes = nil
return sel
@ -164,7 +158,7 @@ var reduceTestTable = []struct {
},
{
name: "include all filter none",
sel: func() Selector {
sel: func() mockSel {
sel := stubSelector()
sel.Filters[0] = scope(stubScope("none"))
sel.Excludes = nil
@ -175,7 +169,7 @@ var reduceTestTable = []struct {
},
{
name: "include all exclude all",
sel: func() Selector {
sel: func() mockSel {
sel := stubSelector()
sel.Filters = nil
return sel
@ -185,7 +179,7 @@ var reduceTestTable = []struct {
},
{
name: "include all exclude none",
sel: func() Selector {
sel: func() mockSel {
sel := stubSelector()
sel.Filters = nil
sel.Excludes[0] = scope(stubScope("none"))
@ -196,7 +190,7 @@ var reduceTestTable = []struct {
},
{
name: "filter all exclude all",
sel: func() Selector {
sel: func() mockSel {
sel := stubSelector()
sel.Includes = nil
return sel
@ -206,7 +200,7 @@ var reduceTestTable = []struct {
},
{
name: "filter all exclude none",
sel: func() Selector {
sel: func() mockSel {
sel := stubSelector()
sel.Includes = nil
sel.Excludes[0] = scope(stubScope("none"))
@ -234,7 +228,7 @@ func (suite *SelectorScopesSuite) TestReduce() {
for _, test := range reduceTestTable {
suite.T().Run(test.name, func(t *testing.T) {
ds := deets()
result := reduce[mockScope](&ds, test.sel(), dataCats)
result := reduce[mockScope](&ds, test.sel().Selector, dataCats)
require.NotNil(t, result)
assert.Len(t, result.Entries, test.expectLen)
})

View File

@ -23,21 +23,10 @@ var ErrorBadSelectorCast = errors.New("wrong selector service type")
const (
scopeKeyCategory = "category"
scopeKeyGranularity = "granularity"
scopeKeyInfoFilter = "info_filter"
scopeKeyResource = "resource"
scopeKeyDataType = "type"
)
// The granularity exprerssed by the scope. Groups imply non-item granularity,
// such as a directory. Items are individual files or objects.
// Filters are properties that search over service-specific info
const (
Group = "group"
Item = "item"
Filter = "filter"
)
// The granularity exprerssed by the scope. Groups imply non-item granularity,
// such as a directory. Items are individual files or objects.
const (
@ -191,23 +180,43 @@ type Printable struct {
Includes map[string][]string `json:"includes,omitempty"`
}
// Printable is the minimized display of a selector, formatted for human readability.
// This transformer assumes that the scopeKeyResource and scopeKeyDataType have been
// added to all scopes as they were created. It is unable to infer resource or data
// type values from existing scope values.
func (s Selector) Printable() Printable {
// ToPrintable creates the minimized display of a selector, formatted for human readability.
func (s Selector) ToPrintable() Printable {
switch s.Service {
case ServiceExchange:
r, err := s.ToExchangeRestore()
if err != nil {
return Printable{}
}
return r.Printable()
case ServiceOneDrive:
r, err := s.ToOneDriveBackup()
if err != nil {
return Printable{}
}
return r.Printable()
}
return 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(s.Excludes),
Filters: toResourceTypeMap(s.Filters),
Includes: toResourceTypeMap(s.Includes),
Excludes: toResourceTypeMap[T](s.Excludes),
Filters: toResourceTypeMap[T](s.Filters),
Includes: toResourceTypeMap[T](s.Includes),
}
}
// Resources generates a tabular-readable output of the resources in Printable.
// Only the first (arbitrarily picked) resource is displayed. All others are
// simply counted. If no inclusions exist, uses Filters. If no filters exist,
// defaults to "All".
// defaults to "None".
// Resource refers to the top-level entity in the service. User for Exchange,
// Site for sharepoint, etc.
func (p Printable) Resources() string {
@ -217,7 +226,7 @@ func (p Printable) Resources() string {
}
if len(s) == 0 {
s = "All"
s = "None"
}
return s
@ -243,22 +252,23 @@ func resourcesShortFormat(m map[string][]string) string {
// Transforms the slice to a single map.
// Keys are each map's scopeKeyResource value.
// Values are the set of all scopeKeyDataTypes for a given resource.
func toResourceTypeMap(ms []scope) map[string][]string {
if len(ms) == 0 {
func toResourceTypeMap[T scopeT](s []scope) map[string][]string {
if len(s) == 0 {
return nil
}
r := make(map[string][]string)
for _, m := range ms {
res := m[scopeKeyResource]
for _, sc := range s {
t := T(sc)
res := sc[t.categorizer().rootCat().String()]
k := res.Target
if res.Target == AnyTgt {
k = All
}
r[k] = addToSet(r[k], split(m[scopeKeyDataType].Target))
r[k] = addToSet(r[k], split(sc[scopeKeyDataType].Target))
}
return r

View File

@ -53,13 +53,21 @@ func (suite *SelectorSuite) TestPrintable_IncludedResources() {
p := sel.Printable()
res := p.Resources()
assert.Equal(t, stubResource, res, "resource should state only the stub")
assert.Equal(t, "All", res, "stub starts out as an all-pass")
stubWithResource := func(resource string) scope {
ss := stubScope("")
ss[rootCatStub.String()] = filterize(resource)
return scope(ss)
}
sel.Includes = []scope{
scope(stubScope("")),
{scopeKeyResource: filterize("smarf"), scopeKeyDataType: filterize(unknownCatStub.String())},
{scopeKeyResource: filterize("smurf"), scopeKeyDataType: filterize(unknownCatStub.String())},
stubWithResource("foo"),
stubWithResource("smarf"),
stubWithResource("fnords"),
}
p = sel.Printable()
res = p.Resources()
@ -68,12 +76,12 @@ func (suite *SelectorSuite) TestPrintable_IncludedResources() {
p.Includes = nil
res = p.Resources()
assert.Equal(t, stubResource, res, "resource on filters should state only the stub")
assert.Equal(t, "All", res, "filters is also an all-pass")
p.Filters = nil
res = p.Resources()
assert.Equal(t, "All", res, "resource with no Includes or Filters should state All")
assert.Equal(t, "None", res, "resource with no Includes or Filters should state None")
}
func (suite *SelectorSuite) TestToResourceTypeMap() {
@ -86,7 +94,7 @@ func (suite *SelectorSuite) TestToResourceTypeMap() {
name: "single scope",
input: []scope{scope(stubScope(""))},
expect: map[string][]string{
stubResource: {rootCatStub.String()},
"All": {rootCatStub.String()},
},
},
{
@ -94,12 +102,12 @@ func (suite *SelectorSuite) TestToResourceTypeMap() {
input: []scope{
scope(stubScope("")),
{
scopeKeyResource: filterize("smarf"),
rootCatStub.String(): filterize("smarf"),
scopeKeyDataType: filterize(unknownCatStub.String()),
},
},
expect: map[string][]string{
stubResource: {rootCatStub.String()},
"All": {rootCatStub.String()},
"smarf": {unknownCatStub.String()},
},
},
@ -108,18 +116,18 @@ func (suite *SelectorSuite) TestToResourceTypeMap() {
input: []scope{
scope(stubScope("")),
{
scopeKeyResource: filterize(stubResource),
rootCatStub.String(): filterize(AnyTgt),
scopeKeyDataType: filterize("other"),
},
},
expect: map[string][]string{
stubResource: {rootCatStub.String(), "other"},
"All": {rootCatStub.String(), "other"},
},
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
rtm := toResourceTypeMap(test.input)
rtm := toResourceTypeMap[mockScope](test.input)
assert.Equal(t, test.expect, rtm)
})
}