clean out scope value chaff (#731)
This commit is contained in:
parent
25ce11b2c6
commit
a226035c23
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
})
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user