Expand selectors package Reduce tests (#925)

## Description

Add test data and more complex tests for the selectors package. This helps codify the interface behavior of selectors which can help avoid surprises in the future

## Type of change

<!--- Please check the type of change your PR introduces: --->
- [ ] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [x] 🤖 Test
- [ ] 💻 CI/Deployment
- [ ] 🐹 Trivial/Minor

## Issue(s)

* #913 

## Test Plan

<!-- How will this be tested prior to merging.-->
- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
ashmrtn 2022-09-21 16:15:28 -07:00 committed by GitHub
parent c1a6086a2a
commit f2e767b3c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 403 additions and 0 deletions

View File

@ -36,6 +36,8 @@ type (
}
)
var _ Reducer = &ExchangeRestore{}
// NewExchange produces a new Selector with the service set to ServiceExchange.
func NewExchangeBackup() *ExchangeBackup {
src := ExchangeBackup{

View File

@ -1,12 +1,14 @@
package selectors
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/pkg/errors"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/filters"
)
@ -53,6 +55,10 @@ var (
// It is not used aside from printing resources.
const All = "All"
type Reducer interface {
Reduce(context.Context, *details.Details) *details.Details
}
// ---------------------------------------------------------------------------
// Selector
// ---------------------------------------------------------------------------

View File

@ -0,0 +1,179 @@
package selectors_test
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/selectors/testdata"
)
type SelectorReduceSuite struct {
suite.Suite
}
func TestSelectorReduceSuite(t *testing.T) {
suite.Run(t, new(SelectorReduceSuite))
}
func (suite *SelectorReduceSuite) TestReduce() {
ctx := context.Background()
allDetails := testdata.GetDetailsSet()
table := []struct {
name string
selFunc func() selectors.Reducer
expected []details.DetailsEntry
}{
{
name: "ExchangeAllMail",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Include(sel.Mails(
selectors.Any(),
selectors.Any(),
selectors.Any(),
))
return sel
},
expected: testdata.ExchangeEmailItems,
},
{
name: "ExchangeMailSubject",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Filter(sel.MailSubject("foo"))
return sel
},
expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
},
{
name: "ExchangeMailSubjectExcludeItem",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Filter(sel.MailSender("a-person"))
sel.Exclude(sel.Mails(
selectors.Any(),
selectors.Any(),
[]string{testdata.ExchangeEmailItemPath2.ShortRef()},
))
return sel
},
expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
},
{
name: "ExchangeMailSender",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Filter(sel.MailSender("a-person"))
return sel
},
expected: testdata.ExchangeEmailItems,
},
{
name: "ExchangeMailReceivedTime",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Filter(sel.MailReceivedBefore(
common.FormatTime(testdata.Time1.Add(time.Second)),
))
return sel
},
expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
},
{
name: "ExchangeMailID",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Include(sel.Mails(
selectors.Any(),
selectors.Any(),
[]string{testdata.ExchangeEmailItemPath1.Item()},
))
return sel
},
expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
},
{
name: "ExchangeMailShortRef",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Include(sel.Mails(
selectors.Any(),
selectors.Any(),
[]string{testdata.ExchangeEmailItemPath1.ShortRef()},
))
return sel
},
expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
},
{
name: "ExchangeAllEventsAndMailWithSubject",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Include(sel.Events(
selectors.Any(),
selectors.Any(),
selectors.Any(),
))
sel.Filter(sel.MailSubject("foo"))
return sel
},
expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
},
{
name: "ExchangeEventsAndMailWithSubject",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Filter(sel.EventSubject("foo"))
sel.Filter(sel.MailSubject("foo"))
return sel
},
expected: []details.DetailsEntry{},
},
{
name: "ExchangeAll",
selFunc: func() selectors.Reducer {
sel := selectors.NewExchangeRestore()
sel.Include(sel.Users(
selectors.Any(),
))
return sel
},
expected: append(
append(
append(
[]details.DetailsEntry{},
testdata.ExchangeEmailItems...),
testdata.ExchangeContactsItems...),
testdata.ExchangeEventsItems...,
),
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
test := test
t.Parallel()
output := test.selFunc().Reduce(ctx, allDetails)
assert.ElementsMatch(t, test.expected, output.Entries)
})
}
}

216
src/pkg/selectors/testdata/details.go vendored Normal file
View File

@ -0,0 +1,216 @@
package testdata
import (
stdpath "path"
"time"
"github.com/alcionai/corso/src/internal/path"
"github.com/alcionai/corso/src/pkg/backup/details"
)
// mustParsePath takes a string representing a resource path and returns a path
// instance. Panics if the path cannot be parsed. Useful for simple variable
// assignments.
func mustParsePath(ref string, isItem bool) path.Path {
p, err := path.FromDataLayerPath(ref, isItem)
if err != nil {
panic(err)
}
return p
}
// mustAppendPath takes a Path, string representing a path element, and whether
// the element is an item and returns a path instance representing the original
// path with the element appended to it. Panics if the path cannot be parsed.
// Useful for simple variable assignments.
func mustAppendPath(p path.Path, newElement string, isItem bool) path.Path {
newP, err := p.Append(newElement, isItem)
if err != nil {
panic(err)
}
return newP
}
const (
ItemName1 = "item1"
ItemName2 = "item2"
)
var (
Time1 = time.Date(2022, 9, 21, 10, 0, 0, 0, time.UTC)
Time2 = time.Date(2022, 10, 21, 10, 0, 0, 0, time.UTC)
ExchangeEmailBasePath = mustParsePath("tenant-id/exchange/user-id/email/Inbox/subfolder", false)
ExchangeEmailItemPath1 = mustAppendPath(ExchangeEmailBasePath, ItemName1, true)
ExchangeEmailItemPath2 = mustAppendPath(ExchangeEmailBasePath, ItemName2, true)
ExchangeEmailItems = []details.DetailsEntry{
{
RepoRef: ExchangeEmailItemPath1.String(),
ShortRef: ExchangeEmailItemPath1.ShortRef(),
ParentRef: ExchangeEmailItemPath1.ToBuilder().Dir().ShortRef(),
ItemInfo: details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: details.ExchangeMail,
Sender: "a-person",
Subject: "foo",
Received: Time1,
},
},
},
{
RepoRef: ExchangeEmailItemPath2.String(),
ShortRef: ExchangeEmailItemPath2.ShortRef(),
ParentRef: ExchangeEmailItemPath2.ToBuilder().Dir().ShortRef(),
ItemInfo: details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: details.ExchangeMail,
Sender: "a-person",
Subject: "bar",
Received: Time2,
},
},
},
}
ExchangeContactsBasePath = mustParsePath("tenant-id/exchange/user-id/contacts/contacts", false)
ExchangeContactsItemPath1 = mustAppendPath(ExchangeContactsBasePath, ItemName1, true)
ExchangeContactsItemPath2 = mustAppendPath(ExchangeContactsBasePath, ItemName2, true)
ExchangeContactsItems = []details.DetailsEntry{
{
RepoRef: ExchangeContactsItemPath1.String(),
ShortRef: ExchangeContactsItemPath1.ShortRef(),
ParentRef: ExchangeContactsItemPath1.ToBuilder().Dir().ShortRef(),
ItemInfo: details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: details.ExchangeContact,
ContactName: "a-person",
},
},
},
{
RepoRef: ExchangeContactsItemPath2.String(),
ShortRef: ExchangeContactsItemPath2.ShortRef(),
ParentRef: ExchangeContactsItemPath2.ToBuilder().Dir().ShortRef(),
ItemInfo: details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: details.ExchangeContact,
ContactName: "another-person",
},
},
},
}
ExchangeEventsBasePath = mustParsePath("tenant-id/exchange/user-id/events/holidays", false)
ExchangeEventsItemPath1 = mustAppendPath(ExchangeEventsBasePath, ItemName1, true)
ExchangeEventsItemPath2 = mustAppendPath(ExchangeEventsBasePath, ItemName2, true)
ExchangeEventsItems = []details.DetailsEntry{
{
RepoRef: ExchangeEventsItemPath1.String(),
ShortRef: ExchangeEventsItemPath1.ShortRef(),
ParentRef: ExchangeEventsItemPath1.ToBuilder().Dir().ShortRef(),
ItemInfo: details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: details.ExchangeEvent,
Organizer: "a-person",
Subject: "foo",
EventStart: Time1,
EventRecurs: false,
},
},
},
{
RepoRef: ExchangeEventsItemPath2.String(),
ShortRef: ExchangeEventsItemPath2.ShortRef(),
ParentRef: ExchangeEventsItemPath2.ToBuilder().Dir().ShortRef(),
ItemInfo: details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: details.ExchangeEvent,
Organizer: "a-person",
Subject: "foo",
EventStart: Time2,
EventRecurs: true,
},
},
},
}
OneDriveBasePath = mustParsePath("tenant-id/onedrive/user-id/files/folder/subfolder", false)
OneDriveItemPath1 = mustAppendPath(OneDriveBasePath, ItemName1, true)
OneDriveItemPath2 = mustAppendPath(OneDriveBasePath, ItemName2, true)
OneDriveItems = []details.DetailsEntry{
{
RepoRef: OneDriveItemPath1.String(),
ShortRef: OneDriveItemPath1.ShortRef(),
ParentRef: OneDriveItemPath1.ToBuilder().Dir().ShortRef(),
ItemInfo: details.ItemInfo{
OneDrive: &details.OneDriveInfo{
ItemType: details.OneDriveItem,
ParentPath: stdpath.Join(
append(
[]string{
"drives",
"foo",
"root:",
},
OneDriveItemPath1.Folders()...,
)...,
),
ItemName: OneDriveItemPath1.Item() + "name",
},
},
},
{
RepoRef: OneDriveItemPath2.String(),
ShortRef: OneDriveItemPath2.ShortRef(),
ParentRef: OneDriveItemPath2.ToBuilder().Dir().ShortRef(),
ItemInfo: details.ItemInfo{
OneDrive: &details.OneDriveInfo{
ItemType: details.OneDriveItem,
ParentPath: stdpath.Join(
append(
[]string{
"drives",
"foo",
"root:",
},
OneDriveItemPath2.Folders()...,
)...,
),
ItemName: OneDriveItemPath2.Item() + "name",
},
},
},
}
)
func GetDetailsSet() *details.Details {
entries := []details.DetailsEntry{}
for _, e := range ExchangeEmailItems {
entries = append(entries, e)
}
for _, e := range ExchangeContactsItems {
entries = append(entries, e)
}
for _, e := range ExchangeEventsItems {
entries = append(entries, e)
}
for _, e := range OneDriveItems {
entries = append(entries, e)
}
return &details.Details{
DetailsModel: details.DetailsModel{
Entries: entries,
},
}
}