corso/src/pkg/selectors/exchange_test.go
2024-01-28 14:52:17 +05:30

1661 lines
43 KiB
Go

package selectors
import (
"strings"
"testing"
"time"
"github.com/alcionai/clues"
"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/dttm"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/filters"
"github.com/alcionai/corso/src/pkg/path"
)
type ExchangeSelectorSuite struct {
tester.Suite
}
func TestExchangeSelectorSuite(t *testing.T) {
suite.Run(t, &ExchangeSelectorSuite{Suite: tester.NewUnitSuite(t)})
}
func (suite *ExchangeSelectorSuite) TestNewExchangeBackup() {
t := suite.T()
eb := NewExchangeBackup(nil)
assert.Equal(t, eb.Service, ServiceExchange)
assert.NotZero(t, eb.Scopes())
}
func (suite *ExchangeSelectorSuite) TestToExchangeBackup() {
t := suite.T()
eb := NewExchangeBackup(nil)
s := eb.Selector
eb, err := s.ToExchangeBackup()
require.NoError(t, err, clues.ToCore(err))
assert.Equal(t, eb.Service, ServiceExchange)
assert.NotZero(t, eb.Scopes())
}
func (suite *ExchangeSelectorSuite) TestNewExchangeRestore() {
t := suite.T()
er := NewExchangeRestore(nil)
assert.Equal(t, er.Service, ServiceExchange)
assert.NotZero(t, er.Scopes())
}
func (suite *ExchangeSelectorSuite) TestToExchangeRestore() {
t := suite.T()
eb := NewExchangeRestore(nil)
s := eb.Selector
eb, err := s.ToExchangeRestore()
require.NoError(t, err, clues.ToCore(err))
assert.Equal(t, eb.Service, ServiceExchange)
assert.NotZero(t, eb.Scopes())
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Contacts() {
t := suite.T()
const (
user = "user"
folder = AnyTgt
c1 = "c1"
c2 = "c2"
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.Contacts([]string{folder}, []string{c1, c2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeContactFolder: {folder},
ExchangeContact: {c1, c2},
})
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Contacts() {
t := suite.T()
const (
user = "user"
folder = AnyTgt
c1 = "c1"
c2 = "c2"
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.Contacts([]string{folder}, []string{c1, c2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeContactFolder: {folder},
ExchangeContact: {c1, c2},
})
assert.Equal(t, sel.Scopes()[0].Category(), ExchangeContact)
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_ContactFolders() {
t := suite.T()
const (
user = "user"
f1 = "f1"
f2 = "f2"
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.ContactFolders([]string{f1, f2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeContactFolder: {f1, f2},
ExchangeContact: Any(),
})
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_ContactFolders() {
t := suite.T()
const (
user = "user"
f1 = "f1"
f2 = "f2"
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.ContactFolders([]string{f1, f2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeContactFolder: {f1, f2},
ExchangeContact: Any(),
})
assert.Equal(t, sel.Scopes()[0].Category(), ExchangeContactFolder)
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Events() {
t := suite.T()
const (
user = "user"
e1 = "e1"
e2 = "e2"
c1 = "c1"
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.Events([]string{c1}, []string{e1, e2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeEventCalendar: {c1},
ExchangeEvent: {e1, e2},
})
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_EventCalendars() {
t := suite.T()
const (
user = "user"
c1 = "c1"
c2 = "c2"
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.EventCalendars([]string{c1, c2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeEventCalendar: {c1, c2},
ExchangeEvent: Any(),
})
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Events() {
t := suite.T()
const (
user = "user"
e1 = "e1"
e2 = "e2"
c1 = "c1"
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.Events([]string{c1}, []string{e1, e2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeEventCalendar: {c1},
ExchangeEvent: {e1, e2},
})
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_EventCalendars() {
t := suite.T()
const (
user = "user"
c1 = "c1"
c2 = "c2"
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.EventCalendars([]string{c1, c2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeEventCalendar: {c1, c2},
ExchangeEvent: Any(),
})
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Mails() {
t := suite.T()
const (
user = "user"
folder = AnyTgt
m1 = "m1"
m2 = "m2"
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.Mails([]string{folder}, []string{m1, m2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeMailFolder: {folder},
ExchangeMail: {m1, m2},
})
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Mails() {
t := suite.T()
const (
user = "user"
folder = AnyTgt
m1 = "m1"
m2 = "m2"
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.Mails([]string{folder}, []string{m1, m2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeMailFolder: {folder},
ExchangeMail: {m1, m2},
})
assert.Equal(t, sel.Scopes()[0].Category(), ExchangeMail)
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_MailFolders() {
t := suite.T()
const (
user = "user"
f1 = "f1"
f2 = "f2"
)
sel := NewExchangeBackup([]string{user})
sel.Exclude(sel.MailFolders([]string{f1, f2}))
scopes := sel.Excludes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeMailFolder: {f1, f2},
ExchangeMail: Any(),
})
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_MailFolders() {
t := suite.T()
const (
user = "user"
f1 = "f1"
f2 = "f2"
)
sel := NewExchangeBackup([]string{user})
sel.Include(sel.MailFolders([]string{f1, f2}))
scopes := sel.Includes
require.Len(t, scopes, 1)
scopeMustHave(
t,
ExchangeScope(scopes[0]),
map[categorizer][]string{
ExchangeMailFolder: {f1, f2},
ExchangeMail: Any(),
})
assert.Equal(t, sel.Scopes()[0].Category(), ExchangeMailFolder)
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_AllData() {
t := suite.T()
const (
u1 = "u1"
u2 = "u2"
)
sel := NewExchangeBackup([]string{u1, u2})
sel.Exclude(sel.AllData())
scopes := sel.Excludes
require.Len(t, scopes, 3)
for _, sc := range scopes {
if sc[scopeKeyCategory].Compare(ExchangeContactFolder.String()) {
scopeMustHave(
t,
ExchangeScope(sc),
map[categorizer][]string{
ExchangeContact: Any(),
ExchangeContactFolder: Any(),
})
}
if sc[scopeKeyCategory].Compare(ExchangeEvent.String()) {
scopeMustHave(
t,
ExchangeScope(sc),
map[categorizer][]string{
ExchangeEvent: Any(),
})
}
if sc[scopeKeyCategory].Compare(ExchangeMailFolder.String()) {
scopeMustHave(
t,
ExchangeScope(sc),
map[categorizer][]string{
ExchangeMail: Any(),
ExchangeMailFolder: Any(),
})
}
}
}
func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_AllData() {
t := suite.T()
const (
u1 = "u1"
u2 = "u2"
)
sel := NewExchangeBackup([]string{u1, u2})
sel.Include(sel.AllData())
scopes := sel.Includes
require.Len(t, scopes, 3)
for _, sc := range scopes {
if sc[scopeKeyCategory].Compare(ExchangeContactFolder.String()) {
scopeMustHave(
t,
ExchangeScope(sc),
map[categorizer][]string{
ExchangeContact: Any(),
ExchangeContactFolder: Any(),
})
}
if sc[scopeKeyCategory].Compare(ExchangeEvent.String()) {
scopeMustHave(
t,
ExchangeScope(sc),
map[categorizer][]string{
ExchangeEvent: Any(),
})
}
if sc[scopeKeyCategory].Compare(ExchangeMailFolder.String()) {
scopeMustHave(
t,
ExchangeScope(sc),
map[categorizer][]string{
ExchangeMail: Any(),
ExchangeMailFolder: Any(),
})
}
}
}
func (suite *ExchangeSelectorSuite) TestExchangeBackup_Scopes() {
eb := NewExchangeBackup(Any())
eb.Include(eb.AllData())
scopes := eb.Scopes()
assert.Len(suite.T(), scopes, 3)
for _, sc := range scopes {
cat := sc.Category()
suite.Run(cat.String(), func() {
t := suite.T()
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 *ExchangeSelectorSuite) TestExchangeScope_Category() {
table := []struct {
is exchangeCategory
expect exchangeCategory
check assert.ComparisonAssertionFunc
}{
{ExchangeCategoryUnknown, ExchangeCategoryUnknown, assert.Equal},
{ExchangeCategoryUnknown, ExchangeUser, assert.NotEqual},
{ExchangeContact, ExchangeContact, assert.Equal},
{ExchangeContact, ExchangeMailFolder, assert.NotEqual},
{ExchangeContactFolder, ExchangeContactFolder, assert.Equal},
{ExchangeContactFolder, ExchangeMailFolder, assert.NotEqual},
{ExchangeEvent, ExchangeEvent, assert.Equal},
{ExchangeEvent, ExchangeEventCalendar, assert.NotEqual},
{ExchangeEventCalendar, ExchangeEventCalendar, assert.Equal},
{ExchangeEvent, ExchangeContact, assert.NotEqual},
{ExchangeMail, ExchangeMail, assert.Equal},
{ExchangeMail, ExchangeMailFolder, assert.NotEqual},
{ExchangeMailFolder, ExchangeMailFolder, assert.Equal},
{ExchangeMailFolder, ExchangeContactFolder, assert.NotEqual},
{ExchangeUser, ExchangeUser, assert.Equal},
{ExchangeUser, ExchangeCategoryUnknown, assert.NotEqual},
}
for _, test := range table {
suite.Run(test.is.String()+test.expect.String(), func() {
eb := NewExchangeBackup(Any())
eb.Includes = []scope{
{scopeKeyCategory: filters.Identity(test.is.String())},
}
scope := eb.Scopes()[0]
test.check(suite.T(), test.expect, scope.Category())
})
}
}
func (suite *ExchangeSelectorSuite) TestExchangeScope_IncludesCategory() {
table := []struct {
is exchangeCategory
expect exchangeCategory
check assert.BoolAssertionFunc
}{
{ExchangeCategoryUnknown, ExchangeCategoryUnknown, assert.False},
{ExchangeCategoryUnknown, ExchangeUser, assert.True},
{ExchangeContact, ExchangeContactFolder, assert.True},
{ExchangeContact, ExchangeMailFolder, assert.False},
{ExchangeContactFolder, ExchangeContact, assert.True},
{ExchangeContactFolder, ExchangeMailFolder, assert.False},
{ExchangeContactFolder, ExchangeEventCalendar, assert.False},
{ExchangeEvent, ExchangeUser, assert.True},
{ExchangeEvent, ExchangeContact, assert.False},
{ExchangeEvent, ExchangeEventCalendar, assert.True},
{ExchangeEvent, ExchangeContactFolder, assert.False},
{ExchangeEventCalendar, ExchangeEvent, assert.True},
{ExchangeEventCalendar, ExchangeEventCalendar, assert.True},
{ExchangeEventCalendar, ExchangeUser, assert.True},
{ExchangeEventCalendar, ExchangeCategoryUnknown, assert.False},
{ExchangeMail, ExchangeMailFolder, assert.True},
{ExchangeMail, ExchangeContact, assert.False},
{ExchangeMailFolder, ExchangeMail, assert.True},
{ExchangeMailFolder, ExchangeContactFolder, assert.False},
{ExchangeMailFolder, ExchangeEventCalendar, assert.False},
{ExchangeUser, ExchangeUser, assert.True},
{ExchangeUser, ExchangeCategoryUnknown, assert.True},
{ExchangeUser, ExchangeMail, assert.True},
{ExchangeUser, ExchangeEventCalendar, assert.True},
}
for _, test := range table {
suite.Run(test.is.String()+test.expect.String(), func() {
eb := NewExchangeBackup(Any())
eb.Includes = []scope{
{scopeKeyCategory: filters.Identity(test.is.String())},
}
scope := eb.Scopes()[0]
test.check(suite.T(), scope.IncludesCategory(test.expect))
})
}
}
func (suite *ExchangeSelectorSuite) TestExchangeScope_Get() {
eb := NewExchangeBackup(Any())
eb.Include(eb.AllData())
scopes := eb.Scopes()
table := []exchangeCategory{
ExchangeContact,
ExchangeContactFolder,
ExchangeEvent,
ExchangeMail,
ExchangeMailFolder,
}
for _, test := range table {
suite.Run(test.String(), func() {
t := suite.T()
for _, sc := range scopes {
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))
}
})
}
}
func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesInfo() {
es := NewExchangeRestore(Any())
const (
name = "smarf mcfnords"
organizer = "cooks@2many.smarf"
sender = "smarf@2many.cooks"
subject = "I have seen the fnords!"
)
var (
epoch = time.Time{}
now = time.Now()
future = now.Add(1 * time.Minute)
)
infoWith := func(itype details.ItemType) details.ItemInfo {
return details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: itype,
ContactName: name,
EventRecurs: true,
EventStart: now,
Organizer: organizer,
Sender: sender,
Subject: subject,
Received: now,
},
}
}
table := []struct {
name string
itype details.ItemType
scope []ExchangeScope
expect assert.BoolAssertionFunc
}{
{"any mail with a sender", details.ExchangeMail, es.MailSender(AnyTgt), assert.True},
{"no mail, regardless of sender", details.ExchangeMail, es.MailSender(NoneTgt), assert.False},
{"mail from a different sender", details.ExchangeMail, es.MailSender("magoo@ma.goo"), assert.False},
{"mail from the matching sender", details.ExchangeMail, es.MailSender(sender), assert.True},
{"mail with any subject", details.ExchangeMail, es.MailSubject(AnyTgt), assert.True},
{"mail with none subject", details.ExchangeMail, es.MailSubject(NoneTgt), assert.False},
{"mail with a different subject", details.ExchangeMail, es.MailSubject("fancy"), assert.False},
{"mail with the matching subject", details.ExchangeMail, es.MailSubject(subject), assert.True},
{"mail with a substring subject match", details.ExchangeMail, es.MailSubject(subject[5:9]), assert.True},
{"mail received after the epoch", details.ExchangeMail, es.MailReceivedAfter(dttm.Format(epoch)), assert.True},
{"mail received after now", details.ExchangeMail, es.MailReceivedAfter(dttm.Format(now)), assert.False},
{
"mail received after sometime later",
details.ExchangeMail,
es.MailReceivedAfter(dttm.Format(future)),
assert.False,
},
{
"mail received before the epoch",
details.ExchangeMail,
es.MailReceivedBefore(dttm.Format(epoch)),
assert.False,
},
{"mail received before now", details.ExchangeMail, es.MailReceivedBefore(dttm.Format(now)), assert.False},
{
"mail received before sometime later",
details.ExchangeMail,
es.MailReceivedBefore(dttm.Format(future)),
assert.True,
},
{"event with any organizer", details.ExchangeEvent, es.EventOrganizer(AnyTgt), assert.True},
{"event with none organizer", details.ExchangeEvent, es.EventOrganizer(NoneTgt), assert.False},
{"event with a different organizer", details.ExchangeEvent, es.EventOrganizer("fancy"), assert.False},
{"event with the matching organizer", details.ExchangeEvent, es.EventOrganizer(organizer), assert.True},
{"event that recurs", details.ExchangeEvent, es.EventRecurs("true"), assert.True},
{"event that does not recur", details.ExchangeEvent, es.EventRecurs("false"), assert.False},
{"event starting after the epoch", details.ExchangeEvent, es.EventStartsAfter(dttm.Format(epoch)), assert.True},
{"event starting after now", details.ExchangeEvent, es.EventStartsAfter(dttm.Format(now)), assert.False},
{
"event starting after sometime later",
details.ExchangeEvent,
es.EventStartsAfter(dttm.Format(future)),
assert.False,
},
{
"event starting before the epoch",
details.ExchangeEvent,
es.EventStartsBefore(dttm.Format(epoch)),
assert.False,
},
{"event starting before now", details.ExchangeEvent, es.EventStartsBefore(dttm.Format(now)), assert.False},
{
"event starting before sometime later",
details.ExchangeEvent,
es.EventStartsBefore(dttm.Format(future)),
assert.True,
},
{"event with any subject", details.ExchangeEvent, es.EventSubject(AnyTgt), assert.True},
{"event with none subject", details.ExchangeEvent, es.EventSubject(NoneTgt), assert.False},
{"event with a different subject", details.ExchangeEvent, es.EventSubject("fancy"), assert.False},
{"event with the matching subject", details.ExchangeEvent, es.EventSubject(subject), assert.True},
{"contact with a different name", details.ExchangeContact, es.ContactName("blarps"), assert.False},
{"contact with the same name", details.ExchangeContact, es.ContactName(name), assert.True},
{"contact with a subname search", details.ExchangeContact, es.ContactName(name[2:5]), assert.True},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
scopes := setScopesToDefault(test.scope)
for _, scope := range scopes {
test.expect(t, scope.matchesInfo(infoWith(test.itype)))
}
})
}
}
func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesPath() {
const (
usr = "userID"
fID1 = "mf_id_1.d"
fld1 = "mailFolder"
fID2 = "mf_id_2.d"
fld2 = "subFolder"
mail = "mailID"
)
var (
repo = stubPath(suite.T(), usr, []string{fID1, fID2, mail}, path.EmailCategory)
loc = strings.Join([]string{fld1, fld2, mail}, "/")
short = "thisisahashofsomekind"
es = NewExchangeRestore(Any())
ent = details.Entry{
RepoRef: repo.String(),
ShortRef: short,
ItemRef: mail,
LocationRef: loc,
}
)
table := []struct {
name string
scope []ExchangeScope
shortRef string
expect assert.BoolAssertionFunc
}{
{"all items", es.AllData(), "", assert.True},
{"all folders", es.MailFolders(Any()), "", assert.True},
{"no folders", es.MailFolders(None()), "", assert.False},
{"matching folder", es.MailFolders([]string{fld1}), "", assert.True},
{"matching folder id", es.MailFolders([]string{fID1}), "", assert.False},
{"incomplete matching folder", es.MailFolders([]string{"mail"}), "", assert.False},
{"incomplete matching folder ID", es.MailFolders([]string{"mf_id"}), "", assert.False},
{"non-matching folder", es.MailFolders([]string{"smarf"}), "", assert.False},
{"non-matching folder substring", es.MailFolders([]string{fld1 + "_suffix"}), "", assert.False},
{"non-matching folder id substring", es.MailFolders([]string{fID1 + "_suffix"}), "", assert.False},
{"matching folder prefix", es.MailFolders([]string{fld1}, PrefixMatch()), "", assert.True},
{"matching folder ID prefix", es.MailFolders([]string{fID1}, PrefixMatch()), "", assert.False},
{"incomplete folder prefix", es.MailFolders([]string{"mail"}, PrefixMatch()), "", assert.False},
{"matching folder substring", es.MailFolders([]string{"Folder"}), "", assert.False},
{"one of multiple folders", es.MailFolders([]string{"smarf", fld2}), "", assert.True},
{"one of multiple folders by ID", es.MailFolders([]string{"smarf", fID2}), "", assert.False},
{"all mail", es.Mails(Any(), Any()), "", assert.True},
{"no mail", es.Mails(Any(), None()), "", assert.False},
{"matching mail", es.Mails(Any(), []string{mail}), "", assert.True},
{"non-matching mail", es.Mails(Any(), []string{"smarf"}), "", assert.False},
{"one of multiple mails", es.Mails(Any(), []string{"smarf", mail}), "", assert.True},
{"mail short ref", es.Mails(Any(), []string{short}), short, assert.True},
{"non-leaf short ref", es.Mails([]string{short}, []string{"foo"}), short, assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
scopes := setScopesToDefault(test.scope)
var aMatch bool
for _, scope := range scopes {
pvs, err := ExchangeMail.pathValues(repo, ent, Config{})
require.NoError(t, err)
if matchesPathValues(scope, ExchangeMail, pvs) {
aMatch = true
break
}
}
test.expect(t, aMatch)
})
}
}
func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() {
var (
contact = stubPath(
suite.T(),
"uid",
[]string{"cfld", "cid"},
path.ContactsCategory)
event = stubPath(
suite.T(),
"uid",
[]string{"efld", "eid"},
path.EventsCategory)
mail = stubPath(
suite.T(),
"uid",
[]string{"mfld", "mid"},
path.EmailCategory)
contactInSubFolder = stubPath(
suite.T(),
"uid",
[]string{"cfld1/cfld2", "cid"},
path.ContactsCategory)
)
toRR := func(p path.Path) string {
newElems := []string{}
for _, e := range p.Folders() {
newElems = append(newElems, e+".d")
}
joinedFldrs := strings.Join(newElems, "/")
return stubRepoRef(p.Service(), p.Category(), p.ProtectedResource(), joinedFldrs, p.Item())
}
makeDeets := func(refs ...path.Path) *details.Details {
deets := &details.Details{
DetailsModel: details.DetailsModel{
Entries: []details.Entry{},
},
}
for _, r := range refs {
itype := details.UnknownType
switch r {
case contact:
itype = details.ExchangeContact
case event:
itype = details.ExchangeEvent
case mail:
itype = details.ExchangeMail
}
deets.Entries = append(deets.Entries, details.Entry{
RepoRef: toRR(r),
// Don't escape because we assume nice paths.
LocationRef: r.Folder(false),
ItemInfo: details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: itype,
},
},
})
}
return deets
}
table := []struct {
name string
deets *details.Details
makeSelector func() *ExchangeRestore
expect []string
}{
{
"no refs",
makeDeets(),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
[]string{},
},
{
"contact only",
makeDeets(contact),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
[]string{toRR(contact)},
},
{
"event only",
makeDeets(event),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
[]string{toRR(event)},
},
{
"mail only",
makeDeets(mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
[]string{toRR(mail)},
},
{
"all",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
[]string{toRR(contact), toRR(event), toRR(mail)},
},
{
"only match contact",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.Contacts([]string{"cfld"}, []string{"cid"}))
return er
},
[]string{toRR(contact)},
},
{
"only match contactInSubFolder",
makeDeets(contactInSubFolder, contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.ContactFolders([]string{"cfld1/cfld2"}))
return er
},
[]string{toRR(contactInSubFolder)},
},
{
"only match contactInSubFolder by prefix",
makeDeets(contactInSubFolder, contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.ContactFolders([]string{"cfld1/cfld2"}, PrefixMatch()))
return er
},
[]string{toRR(contactInSubFolder)},
},
{
"only match contactInSubFolder by leaf folder",
makeDeets(contactInSubFolder, contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.ContactFolders([]string{"cfld2"}))
return er
},
[]string{toRR(contactInSubFolder)},
},
{
"only match event",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.Events([]string{"efld"}, []string{"eid"}))
return er
},
[]string{toRR(event)},
},
{
"only match mail",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.Mails([]string{"mfld"}, []string{"mid"}))
return er
},
[]string{toRR(mail)},
},
{
"exclude contact",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Exclude(er.Contacts([]string{"cfld"}, []string{"cid"}))
return er
},
[]string{toRR(event), toRR(mail)},
},
{
"exclude event",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Exclude(er.Events([]string{"efld"}, []string{"eid"}))
return er
},
[]string{toRR(contact), toRR(mail)},
},
{
"exclude mail",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Exclude(er.Mails([]string{"mfld"}, []string{"mid"}))
return er
},
[]string{toRR(contact), toRR(event)},
},
{
"filter on mail subject",
func() *details.Details {
ds := makeDeets(mail)
for i := range ds.Entries {
ds.Entries[i].Exchange.Subject = "has a subject"
}
return ds
}(),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Filter(er.MailSubject("subj"))
return er
},
[]string{toRR(mail)},
},
{
"filter on mail subject multiple input categories",
func() *details.Details {
mds := makeDeets(mail)
for i := range mds.Entries {
mds.Entries[i].Exchange.Subject = "has a subject"
}
ds := makeDeets(contact, event)
ds.Entries = append(ds.Entries, mds.Entries...)
return ds
}(),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Filter(er.MailSubject("subj"))
return er
},
[]string{toRR(mail)},
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
ctx, flush := tester.NewContext(t)
defer flush()
sel := test.makeSelector()
results := sel.Reduce(ctx, test.deets, fault.New(true))
paths := results.Paths()
assert.Equal(t, test.expect, paths)
})
}
}
func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce_locationRef() {
var (
contact = stubRepoRef(path.ExchangeService, path.ContactsCategory, "uid", "id5/id6", "cid")
contactLocation = "conts/my_cont"
event = stubRepoRef(path.ExchangeService, path.EventsCategory, "uid", "id1/id2", "eid")
eventLocation = "cal/my_cal"
mail = stubRepoRef(path.ExchangeService, path.EmailCategory, "uid", "id3/id4", "mid")
mailLocation = "inbx/my_mail"
)
makeDeets := func(refs ...string) *details.Details {
deets := &details.Details{
DetailsModel: details.DetailsModel{
Entries: []details.Entry{},
},
}
for _, r := range refs {
var (
location string
itype = details.UnknownType
)
switch r {
case contact:
itype = details.ExchangeContact
location = contactLocation
case event:
itype = details.ExchangeEvent
location = eventLocation
case mail:
itype = details.ExchangeMail
location = mailLocation
}
deets.Entries = append(deets.Entries, details.Entry{
RepoRef: r,
LocationRef: location,
ItemInfo: details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: itype,
},
},
})
}
return deets
}
arr := func(s ...string) []string {
return s
}
table := []struct {
name string
deets *details.Details
makeSelector func() *ExchangeRestore
expect []string
}{
{
"no refs",
makeDeets(),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
[]string{},
},
{
"contact only",
makeDeets(contact),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
arr(contact),
},
{
"event only",
makeDeets(event),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
arr(event),
},
{
"mail only",
makeDeets(mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
arr(mail),
},
{
"all",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
return er
},
arr(contact, event, mail),
},
{
"only match contact",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.Contacts([]string{contactLocation}, []string{"cid"}))
return er
},
arr(contact),
},
{
"only match event",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.Events([]string{eventLocation}, []string{"eid"}))
return er
},
arr(event),
},
{
"only match mail",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore([]string{"uid"})
er.Include(er.Mails([]string{mailLocation}, []string{"mid"}))
return er
},
arr(mail),
},
{
"exclude contact",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Exclude(er.Contacts([]string{contactLocation}, []string{"cid"}))
return er
},
arr(event, mail),
},
{
"exclude event",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Exclude(er.Events([]string{eventLocation}, []string{"eid"}))
return er
},
arr(contact, mail),
},
{
"exclude mail",
makeDeets(contact, event, mail),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Exclude(er.Mails([]string{mailLocation}, []string{"mid"}))
return er
},
arr(contact, event),
},
{
"filter on mail subject",
func() *details.Details {
ds := makeDeets(mail)
for i := range ds.Entries {
ds.Entries[i].Exchange.Subject = "has a subject"
}
return ds
}(),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Filter(er.MailSubject("subj"))
return er
},
arr(mail),
},
{
"filter on mail subject multiple input categories",
func() *details.Details {
mds := makeDeets(mail)
for i := range mds.Entries {
mds.Entries[i].Exchange.Subject = "has a subject"
}
ds := makeDeets(contact, event)
ds.Entries = append(ds.Entries, mds.Entries...)
return ds
}(),
func() *ExchangeRestore {
er := NewExchangeRestore(Any())
er.Include(er.AllData())
er.Filter(er.MailSubject("subj"))
return er
},
arr(mail),
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
ctx, flush := tester.NewContext(t)
defer flush()
sel := test.makeSelector()
results := sel.Reduce(ctx, test.deets, fault.New(true))
paths := results.Paths()
assert.Equal(t, test.expect, paths)
})
}
}
func (suite *ExchangeSelectorSuite) TestScopesByCategory() {
var (
es = NewExchangeRestore(Any())
allData = es.AllData()
contacts = es.ContactFolders(Any())
events = es.EventCalendars(Any())
mail = es.MailFolders(Any())
)
type expect struct {
contact int
event int
mail int
}
type input []scope
makeInput := func(es ...[]ExchangeScope) []scope {
mss := []scope{}
for _, sl := range es {
for _, s := range sl {
mss = append(mss, scope(s))
}
}
return mss
}
cats := map[path.CategoryType]exchangeCategory{
path.ContactsCategory: ExchangeContact,
path.EventsCategory: ExchangeEvent,
path.EmailCategory: ExchangeMail,
}
table := []struct {
name string
scopes input
expect expect
}{
{"contacts only", makeInput(contacts), expect{1, 0, 0}},
{"events only", makeInput(events), expect{0, 1, 0}},
{"mail only", makeInput(mail), expect{0, 0, 1}},
{"all", makeInput(allData, contacts, events, mail), expect{2, 2, 2}},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
result := scopesByCategory[ExchangeScope](test.scopes, cats, false)
assert.Len(t, result[ExchangeContact], test.expect.contact)
assert.Len(t, result[ExchangeEvent], test.expect.event)
assert.Len(t, result[ExchangeMail], test.expect.mail)
})
}
}
func (suite *ExchangeSelectorSuite) TestPasses() {
const (
mid = "mailID"
cat = ExchangeMail
)
short := "thisisahashofsomekind"
entry := details.Entry{
ShortRef: short,
ItemRef: mid,
}
var (
es = NewExchangeRestore(Any())
otherMail = setScopesToDefault(es.Mails(Any(), []string{"smarf"}))
mail = setScopesToDefault(es.Mails(Any(), []string{mid}))
noMail = setScopesToDefault(es.Mails(Any(), None()))
allMail = setScopesToDefault(es.Mails(Any(), Any()))
repo = stubPath(suite.T(), "user", []string{"folder", mid}, path.EmailCategory)
ent = details.Entry{
RepoRef: repo.String(),
}
)
table := []struct {
name string
excludes, filters, includes []ExchangeScope
expect assert.BoolAssertionFunc
}{
{"empty", nil, nil, nil, assert.False},
{"in Mail", nil, nil, mail, assert.True},
{"in Other", nil, nil, otherMail, assert.False},
{"in no Mail", nil, nil, noMail, assert.False},
{"ex None filter mail", allMail, mail, nil, assert.False},
{"ex Mail", mail, nil, allMail, assert.False},
{"ex Other", otherMail, nil, allMail, assert.True},
{"in and ex Mail", mail, nil, mail, assert.False},
{"filter Mail", nil, mail, allMail, assert.True},
{"filter Other", nil, otherMail, allMail, assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
pvs, err := cat.pathValues(repo, ent, Config{})
require.NoError(t, err)
result := passes(
cat,
pvs,
entry,
test.excludes,
test.filters,
test.includes)
test.expect(t, result)
})
}
}
func (suite *ExchangeSelectorSuite) TestContains() {
target := "fnords"
var (
es = NewExchangeRestore(Any())
noMail = setScopesToDefault(es.Mails(None(), None()))
does = setScopesToDefault(es.Mails(Any(), []string{target}))
doesNot = setScopesToDefault(es.Mails(Any(), []string{"smarf"}))
wrongType = setScopesToDefault(es.Contacts(Any(), Any()))
wrongTypeGoodTarget = setScopesToDefault(es.Contacts(Any(), Any()))
)
table := []struct {
name string
scopes []ExchangeScope
expect assert.BoolAssertionFunc
}{
{"no mail", noMail, assert.False},
{"does contain", does, assert.True},
{"does not contain", doesNot, assert.False},
{"wrong type", wrongType, assert.False},
{"wrong type but right target", wrongTypeGoodTarget, assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
var result bool
for _, scope := range test.scopes {
if scope.Matches(ExchangeMail, target) {
result = true
break
}
}
test.expect(t, result)
})
}
}
func (suite *ExchangeSelectorSuite) TestIsAny() {
var (
es = NewExchangeRestore(Any())
specificMail = setScopesToDefault(es.Mails(Any(), []string{"email"}))
anyMail = setScopesToDefault(es.Mails(Any(), Any()))
)
table := []struct {
name string
scopes []ExchangeScope
cat exchangeCategory
expect assert.BoolAssertionFunc
}{
{"specific mail", specificMail, ExchangeMail, assert.False},
{"any mail", anyMail, ExchangeMail, assert.True},
{"wrong category", anyMail, ExchangeEvent, assert.False},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
var result bool
for _, scope := range test.scopes {
if scope.IsAny(test.cat) {
result = true
break
}
}
test.expect(t, result)
})
}
}
func (suite *ExchangeSelectorSuite) TestExchangeCategory_leafCat() {
table := []struct {
cat exchangeCategory
expect exchangeCategory
}{
{exchangeCategory("foo"), exchangeCategory("foo")},
{ExchangeCategoryUnknown, ExchangeCategoryUnknown},
{ExchangeUser, ExchangeUser},
{ExchangeMailFolder, ExchangeMail},
{ExchangeMail, ExchangeMail},
{ExchangeContactFolder, ExchangeContact},
{ExchangeEvent, ExchangeEvent},
}
for _, test := range table {
suite.Run(test.cat.String(), func() {
assert.Equal(suite.T(), test.expect, test.cat.leafCat(), test.cat.String())
})
}
}
func (suite *ExchangeSelectorSuite) TestExchangeCategory_PathValues() {
t := suite.T()
var (
contactPath = stubPath(t, "u", []string{"cfolder.d", "contactitem.d"}, path.ContactsCategory)
contactLoc = stubPath(t, "u", []string{"cfolder", "contactitem"}, path.ContactsCategory)
contactMap = map[categorizer][]string{
ExchangeContactFolder: {contactLoc.Folder(false)},
ExchangeContact: {contactPath.Item(), "contact-short"},
}
contactOnlyNameMap = map[categorizer][]string{
ExchangeContactFolder: {contactLoc.Folder(false)},
ExchangeContact: {"contact-short"},
}
eventPath = stubPath(t, "u", []string{"ecalendar.d", "eventitem.d"}, path.EventsCategory)
eventLoc = stubPath(t, "u", []string{"ecalendar", "eventitem"}, path.EventsCategory)
eventMap = map[categorizer][]string{
ExchangeEventCalendar: {eventLoc.Folder(false)},
ExchangeEvent: {eventPath.Item(), "event-short"},
}
eventOnlyNameMap = map[categorizer][]string{
ExchangeEventCalendar: {eventLoc.Folder(false)},
ExchangeEvent: {"event-short"},
}
mailPath = stubPath(t, "u", []string{"mfolder.d", "mailitem.d"}, path.EmailCategory)
mailLoc = stubPath(t, "u", []string{"mfolder", "mailitem"}, path.EmailCategory)
mailMap = map[categorizer][]string{
ExchangeMailFolder: {mailLoc.Folder(false)},
ExchangeMail: {mailPath.Item(), "mail-short"},
}
mailOnlyNameMap = map[categorizer][]string{
ExchangeMailFolder: {mailLoc.Folder(false)},
ExchangeMail: {"mail-short"},
}
)
table := []struct {
cat exchangeCategory
path path.Path
loc path.Path
short string
expect map[categorizer][]string
expectOnlyName map[categorizer][]string
}{
{ExchangeContact, contactPath, contactLoc, "contact-short", contactMap, contactOnlyNameMap},
{ExchangeEvent, eventPath, eventLoc, "event-short", eventMap, eventOnlyNameMap},
{ExchangeMail, mailPath, mailLoc, "mail-short", mailMap, mailOnlyNameMap},
}
for _, test := range table {
suite.Run(string(test.cat), func() {
t := suite.T()
ent := details.Entry{
RepoRef: test.path.String(),
ShortRef: test.short,
LocationRef: test.loc.Folder(true),
ItemRef: test.path.Item(),
}
pvs, err := test.cat.pathValues(test.path, ent, Config{})
require.NoError(t, err)
for k := range test.expect {
assert.ElementsMatch(t, test.expect[k], pvs[k])
}
pvs, err = test.cat.pathValues(test.path, ent, Config{OnlyMatchItemNames: true})
require.NoError(t, err)
for k := range test.expectOnlyName {
assert.ElementsMatch(t, test.expectOnlyName[k], pvs[k], k)
}
})
}
}
func (suite *ExchangeSelectorSuite) TestExchangeCategory_PathKeys() {
contact := []categorizer{ExchangeContactFolder, ExchangeContact}
event := []categorizer{ExchangeEventCalendar, ExchangeEvent}
mail := []categorizer{ExchangeMailFolder, ExchangeMail}
user := []categorizer{ExchangeUser}
var empty []categorizer
table := []struct {
cat exchangeCategory
expect []categorizer
}{
{ExchangeCategoryUnknown, empty},
{ExchangeContact, contact},
{ExchangeEvent, event},
{ExchangeMail, mail},
{ExchangeUser, user},
}
for _, test := range table {
suite.Run(string(test.cat), func() {
assert.Equal(suite.T(), test.cat.pathKeys(), test.expect)
})
}
}
func (suite *ExchangeSelectorSuite) TestCategoryFromItemType() {
table := []struct {
name string
input details.ItemType
expect exchangeCategory
}{
{
name: "contact",
input: details.ExchangeContact,
expect: ExchangeContact,
},
{
name: "event",
input: details.ExchangeEvent,
expect: ExchangeEvent,
},
{
name: "mail",
input: details.ExchangeMail,
expect: ExchangeMail,
},
{
name: "unknown",
input: details.UnknownType,
expect: ExchangeCategoryUnknown,
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
result := categoryFromItemType(test.input)
assert.Equal(t, test.expect, result)
})
}
}
func (suite *ExchangeSelectorSuite) TestCategory_PathType() {
table := []struct {
cat exchangeCategory
pathType path.CategoryType
}{
{ExchangeCategoryUnknown, path.UnknownCategory},
{ExchangeContact, path.ContactsCategory},
{ExchangeContactFolder, path.ContactsCategory},
{ExchangeEvent, path.EventsCategory},
{ExchangeEventCalendar, path.EventsCategory},
{ExchangeMail, path.EmailCategory},
{ExchangeMailFolder, path.EmailCategory},
{ExchangeUser, path.UnknownCategory},
{ExchangeInfoMailSender, path.EmailCategory},
{ExchangeInfoMailSubject, path.EmailCategory},
{ExchangeInfoMailReceivedAfter, path.EmailCategory},
{ExchangeInfoMailReceivedBefore, path.EmailCategory},
{ExchangeInfoContactName, path.ContactsCategory},
{ExchangeInfoEventOrganizer, path.EventsCategory},
{ExchangeInfoEventRecurs, path.EventsCategory},
{ExchangeInfoEventStartsAfter, path.EventsCategory},
{ExchangeInfoEventStartsBefore, path.EventsCategory},
{ExchangeInfoEventSubject, path.EventsCategory},
}
for _, test := range table {
suite.Run(test.cat.String(), func() {
assert.Equal(suite.T(), test.pathType, test.cat.PathType())
})
}
}
func (suite *ExchangeSelectorSuite) Test_MoreTest() {
t := suite.T()
tests := []struct {
name string
path1 string
path2 string
}{
{
name: "same linux normal path",
path1: "/path/to/dir",
path2: "/path/to/dir",
},
}
for _, test := range tests {
assert.Equal(t, test.path1, test.path2)
}
}