GC: Backup: Events: Filter Calendars with Scope (#900)

## Description
Feature branch enabling filtering based upon `selectors.ExchangeScope`
<!-- Insert PR description-->

## Type of change

<!--- Please check the type of change your PR introduces: --->
- [x] 🌻 Feature

## Issue(s)

<!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. -->
*closes #810<issue>

## Test Plan
- [x]  Unit test
This commit is contained in:
Danny 2022-09-26 13:33:33 -04:00 committed by GitHub
parent 679b32697b
commit 06d2a389d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 421 additions and 176 deletions

View File

@ -58,12 +58,7 @@ func (suite *ExchangeIteratorSuite) TestDescendable() {
}
func loadService(t *testing.T) *exchangeService {
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
require.NoError(t, err)
a := tester.NewM365Account(t)
require.NoError(t, err)
m365, err := a.M365Config()
require.NoError(t, err)
@ -145,7 +140,7 @@ func (suite *ExchangeIteratorSuite) TestIterativeFunctions() {
}, {
name: "Folder Iterative Check Mail",
queryFunction: GetAllFolderNamesForUser,
iterativeFunction: IterateFilterFolderDirectoriesForCollections,
iterativeFunction: IterateFilterContainersForCollections,
scope: mailScope,
transformer: models.CreateMailFolderCollectionResponseFromDiscriminatorValue,
folderNames: map[string]struct{}{
@ -156,7 +151,7 @@ func (suite *ExchangeIteratorSuite) TestIterativeFunctions() {
}, {
name: "Folder Iterative Check Contacts",
queryFunction: GetAllContactFolderNamesForUser,
iterativeFunction: IterateFilterFolderDirectoriesForCollections,
iterativeFunction: IterateFilterContainersForCollections,
scope: contactScope,
transformer: models.CreateContactFolderCollectionResponseFromDiscriminatorValue,
},

View File

@ -5,9 +5,12 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/selectors"
)
type ServiceFunctionsIntegrationSuite struct {
@ -77,6 +80,7 @@ func (suite *ServiceFunctionsIntegrationSuite) TestGetAllCalendars() {
func (suite *ServiceFunctionsIntegrationSuite) TestGetAllContactFolders() {
gs := loadService(suite.T())
user := tester.M365UserID(suite.T())
ctx := context.Background()
table := []struct {
@ -86,14 +90,14 @@ func (suite *ServiceFunctionsIntegrationSuite) TestGetAllContactFolders() {
}{
{
name: "plain lookup",
user: suite.m365UserID,
user: user,
expectCount: assert.Greater,
expectErr: assert.NoError,
},
{
name: "root folder",
contains: "Contact",
user: suite.m365UserID,
user: user,
expectCount: assert.Greater,
expectErr: assert.NoError,
},
@ -106,7 +110,7 @@ func (suite *ServiceFunctionsIntegrationSuite) TestGetAllContactFolders() {
{
name: "nonsense matcher",
contains: "∂ç∂ç∂√≈∂ƒß∂ç√ßç√≈ç√ß∂ƒçß√ß≈∂ƒßç√",
user: suite.m365UserID,
user: user,
expectCount: assert.Equal,
expectErr: assert.NoError,
},
@ -164,3 +168,83 @@ func (suite *ServiceFunctionsIntegrationSuite) TestGetAllMailFolders() {
})
}
}
func (suite *ServiceFunctionsIntegrationSuite) TestCollectContainers() {
ctx := context.Background()
failFast := false
containerCount := 1
t := suite.T()
user := tester.M365UserID(t)
a := tester.NewM365Account(t)
credentials, err := a.M365Config()
require.NoError(t, err)
tests := []struct {
name, contains string
getScope func() selectors.ExchangeScope
expectedCount assert.ComparisonAssertionFunc
}{
{
name: "All Events",
contains: "Birthdays",
expectedCount: assert.Greater,
getScope: func() selectors.ExchangeScope {
sel := selectors.NewExchangeBackup()
sel.Include(sel.EventCalendars([]string{user}, selectors.Any()))
scopes := sel.Scopes()
assert.Equal(t, len(scopes), 1)
return scopes[0]
},
}, {
name: "Default Calendar",
contains: DefaultCalendar,
expectedCount: assert.Equal,
getScope: func() selectors.ExchangeScope {
sel := selectors.NewExchangeBackup()
sel.Include(sel.EventCalendars([]string{user}, []string{DefaultCalendar}))
scopes := sel.Scopes()
assert.Equal(t, len(scopes), 1)
return scopes[0]
},
}, {
name: "Default Mail",
contains: DefaultMailFolder,
expectedCount: assert.Equal,
getScope: func() selectors.ExchangeScope {
sel := selectors.NewExchangeBackup()
sel.Include(sel.MailFolders([]string{user}, []string{DefaultMailFolder}))
scopes := sel.Scopes()
assert.Equal(t, len(scopes), 1)
return scopes[0]
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
qp := graph.QueryParams{
User: user,
Scope: test.getScope(),
FailFast: failFast,
Credentials: credentials,
}
collections := make(map[string]*Collection)
err := CollectFolders(ctx, qp, collections, nil)
assert.NoError(t, err)
test.expectedCount(t, len(collections), containerCount)
keys := make([]string, 0, len(collections))
for k := range collections {
keys = append(keys, k)
}
t.Logf("Collections Made: %v\n", keys)
assert.Contains(t, keys, test.contains)
})
}
}

View File

@ -2,6 +2,7 @@ package exchange
import (
"context"
"fmt"
msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core"
"github.com/microsoftgraph/msgraph-sdk-go/models"
@ -117,6 +118,9 @@ func IterateSelectAllDescendablesForCollections(
// utility function for iterating through events
// and storing events in collections based on
// the calendarID which originates from M365.
// @param pageItem is a CalendarCollectionResponse possessing two populated fields:
// - id - M365 ID
// - Name - Calendar Name
func IterateSelectAllEventsFromCalendars(
ctx context.Context,
qp graph.QueryParams,
@ -124,83 +128,62 @@ func IterateSelectAllEventsFromCalendars(
collections map[string]*Collection,
statusUpdater support.StatusUpdater,
) func(any) bool {
var (
isEnabled bool
service graph.Service
)
return func(pageItem any) bool {
if pageItem == nil {
return true
if !isEnabled {
// Create Collections based on qp.Scope
err := CollectFolders(ctx, qp, collections, statusUpdater)
if err != nil {
errUpdater(
qp.User,
errors.Wrap(err, support.ConnectorStackErrorTrace(err)),
)
return false
}
service, err = createService(qp.Credentials, qp.FailFast)
if err != nil {
errUpdater(qp.User, err)
return false
}
isEnabled = true
}
shell, ok := pageItem.(models.Calendarable)
pageItem = CreateCalendarDisplayable(pageItem)
calendar, ok := pageItem.(displayable)
if !ok {
errUpdater(qp.User, errors.New("casting pageItem to models.Calendarable"))
errUpdater(
qp.User,
fmt.Errorf("unable to parse pageItem into CalendarDisplayable: %T", pageItem),
)
}
if calendar.GetDisplayName() == nil {
return true
}
service, err := createService(qp.Credentials, qp.FailFast)
collection, ok := collections[*calendar.GetDisplayName()]
if !ok {
return true
}
eventIDs, err := ReturnEventIDsFromCalendar(ctx, service, qp.User, *calendar.GetId())
if err != nil {
errUpdater(
qp.User,
errors.Wrap(err, "creating service for IterateSelectAllEventsFromCalendars"))
errors.Wrap(err, support.ConnectorStackErrorTrace(err)))
return true
}
eventResponseable, err := service.Client().
UsersById(qp.User).
CalendarsById(*shell.GetId()).
Events().Get(ctx, nil)
if err != nil {
errUpdater(qp.User, err)
}
directory := shell.GetName()
owner := shell.GetOwner()
// Conditional Guard Checks
if eventResponseable == nil ||
directory == nil ||
owner == nil {
return true
}
eventables := eventResponseable.GetValue()
// Clause is true when Calendar has does not have any events
if eventables == nil {
return true
}
if _, ok := collections[*directory]; !ok {
service, err := createService(qp.Credentials, qp.FailFast)
if err != nil {
errUpdater(qp.User, err)
return true
}
dirPath, err := path.Builder{}.Append(*directory).ToDataLayerExchangePathForCategory(
qp.Credentials.TenantID,
qp.User,
path.EventsCategory,
false,
)
if err != nil {
// we should never hit this error
errUpdater("converting to resource path", err)
return true
}
edc := NewCollection(
qp.User,
dirPath,
events,
service,
statusUpdater,
)
collections[*directory] = &edc
}
for _, event := range eventables {
collections[*directory].AddJob(*event.GetId())
}
collection.jobs = append(collection.jobs, eventIDs...)
return true
}
@ -216,7 +199,11 @@ func IterateAndFilterDescendablesForCollections(
collections map[string]*Collection,
statusUpdater support.StatusUpdater,
) func(any) bool {
var isFilterSet bool
var (
isFilterSet bool
resolver graph.ContainerResolver
cache map[string]string
)
return func(descendItem any) bool {
if !isFilterSet {
@ -230,6 +217,13 @@ func IterateAndFilterDescendablesForCollections(
errUpdater(qp.User, err)
return false
}
// Caches folder directories
cache = make(map[string]string, 0)
resolver, err = maybeGetAndPopulateFolderResolver(ctx, qp, path.EmailCategory)
if err != nil {
errUpdater("getting folder resolver for category "+path.EmailCategory.String(), err)
}
isFilterSet = true
}
@ -240,7 +234,20 @@ func IterateAndFilterDescendablesForCollections(
return true
}
// Saving only messages for the created directories
directory := *message.GetParentFolderId()
folderID := *message.GetParentFolderId()
directory, ok := cache[folderID]
if !ok {
result := translateIDToDirectory(ctx, qp, resolver, folderID)
if result == "" {
errUpdater(qp.User,
errors.New("getCollectionPath experienced error during translateID"))
}
cache[folderID] = result
directory = result
}
if _, ok = collections[directory]; !ok {
return true
}
@ -251,7 +258,65 @@ func IterateAndFilterDescendablesForCollections(
}
}
func IterateFilterFolderDirectoriesForCollections(
func translateIDToDirectory(
ctx context.Context,
qp graph.QueryParams,
resolver graph.ContainerResolver,
directoryID string,
) string {
fullPath, err := getCollectionPath(ctx, qp, resolver, directoryID, path.EmailCategory)
if err != nil {
return ""
}
return fullPath.Folder()
}
func getCategoryAndValidation(es selectors.ExchangeScope) (
optionIdentifier,
path.CategoryType,
func(namePtr *string) bool,
) {
var (
option = scopeToOptionIdentifier(es)
category path.CategoryType
validate func(namePtr *string) bool
)
switch option {
case messages:
category = path.EmailCategory
validate = func(namePtr *string) bool {
if namePtr == nil {
return true
}
return !es.Matches(selectors.ExchangeMailFolder, *namePtr)
}
case contacts:
category = path.ContactsCategory
validate = func(namePtr *string) bool {
if namePtr == nil {
return true
}
return !es.Matches(selectors.ExchangeContactFolder, *namePtr)
}
case events:
category = path.EventsCategory
validate = func(namePtr *string) bool {
if namePtr == nil {
return true
}
return !es.Matches(selectors.ExchangeEventCalendar, *namePtr)
}
}
return option, category, validate
}
func IterateFilterContainersForCollections(
ctx context.Context,
qp graph.QueryParams,
errUpdater func(string, error),
@ -265,30 +330,12 @@ func IterateFilterFolderDirectoriesForCollections(
err error
option optionIdentifier
category path.CategoryType
validate func(string) bool
validate func(*string) bool
)
return func(folderItem any) bool {
folder, ok := folderItem.(displayable)
if !ok {
errUpdater(qp.User, errors.New("casting folderItem to displayable"))
return true
}
if !isSet {
option = scopeToOptionIdentifier(qp.Scope)
switch option {
case messages:
category = path.EmailCategory
validate = func(name string) bool {
return !qp.Scope.Matches(selectors.ExchangeMailFolder, name)
}
case contacts:
category = path.ContactsCategory
validate = func(name string) bool {
return !qp.Scope.Matches(selectors.ExchangeContactFolder, name)
}
}
option, category, validate = getCategoryAndValidation(qp.Scope)
resolver, err = maybeGetAndPopulateFolderResolver(ctx, qp, category)
if err != nil {
@ -298,19 +345,27 @@ func IterateFilterFolderDirectoriesForCollections(
isSet = true
}
// Continue to iterate if folder name is empty
if folder.GetDisplayName() == nil {
if option == events {
folderItem = CreateCalendarDisplayable(folderItem)
}
folder, ok := folderItem.(displayable)
if !ok {
errUpdater(qp.User,
fmt.Errorf("unable to convert input of %T for category: %s", folderItem, category.String()),
)
return true
}
if validate(*folder.GetDisplayName()) {
if validate(folder.GetDisplayName()) {
return true
}
if option == contacts {
collectPath = *folder.GetDisplayName()
} else {
if option == messages {
collectPath = *folder.GetId()
} else {
collectPath = *folder.GetDisplayName()
}
dirPath, err := getCollectionPath(
@ -345,7 +400,7 @@ func IterateFilterFolderDirectoriesForCollections(
service,
statusUpdater,
)
collections[*folder.GetId()] = &temp
collections[*folder.GetDisplayName()] = &temp
return true
}
@ -565,3 +620,53 @@ func ReturnContactIDsFromDirectory(ctx context.Context, gs graph.Service, user,
return stringArray, nil
}
// ReturnEventIDsFromCalendar returns a list of all M365IDs of events of the targeted Calendar.
func ReturnEventIDsFromCalendar(
ctx context.Context,
gs graph.Service,
user, calendarID string,
) ([]string, error) {
ids := []string{}
response, err := gs.Client().
UsersById(user).
CalendarsById(calendarID).
Events().Get(ctx, nil)
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
pageIterator, err := msgraphgocore.NewPageIterator(
response,
gs.Adapter(),
models.CreateEventCollectionResponseFromDiscriminatorValue,
)
callbackFunc := func(pageItem any) bool {
entry, ok := pageItem.(models.Eventable)
if !ok {
err = errors.New("casting pageItem to models.Eventable")
return false
}
ids = append(ids, *entry.GetId())
return true
}
if iterateErr := pageIterator.Iterate(ctx, callbackFunc); iterateErr != nil {
return nil,
errors.Wrap(iterateErr, support.ConnectorStackErrorTrace(err))
}
if err != nil {
return nil, err
}
return ids, nil
}

View File

@ -122,6 +122,8 @@ func RetrieveMessageDataForUser(ctx context.Context, gs graph.Service, user, m36
return gs.Client().UsersById(user).MessagesById(m365ID).Get(ctx, nil)
}
// CollectFolders is a utility function for creating Collections based off parameters found
// in the ExchangeScope found in the graph.QueryParams
func CollectFolders(
ctx context.Context,
qp graph.QueryParams,
@ -149,6 +151,9 @@ func CollectFolders(
case contacts:
query = GetAllContactFolderNamesForUser
transformer = models.CreateContactFolderCollectionResponseFromDiscriminatorValue
case events:
query = GetAllCalendarNamesForUser
transformer = models.CreateCalendarCollectionResponseFromDiscriminatorValue
default:
return fmt.Errorf("unsupported option %s used in CollectFolders", option)
}
@ -176,7 +181,7 @@ func CollectFolders(
err = support.WrapAndAppend(id, e, err)
}
callbackFunc := IterateFilterFolderDirectoriesForCollections(
callbackFunc := IterateFilterContainersForCollections(
ctx,
qp,
errUpdater,

View File

@ -3,7 +3,6 @@ package connector
import (
"bytes"
"context"
"fmt"
"testing"
"time"
@ -14,7 +13,6 @@ import (
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/internal/connector/exchange"
"github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/selectors"
)
@ -85,36 +83,54 @@ func (suite *GraphConnectorIntegrationSuite) TestSetTenantUsers() {
// - events
func (suite *GraphConnectorIntegrationSuite) TestExchangeDataCollection() {
ctx := context.Background()
t := suite.T()
connector := loadConnector(ctx, t)
sel := selectors.NewExchangeBackup()
sel.Include(sel.Users([]string{suite.user}))
collectionList, err := connector.ExchangeDataCollection(context.Background(), sel.Selector)
assert.NotNil(t, collectionList, "collection list")
assert.NoError(t, err)
assert.Zero(t, connector.status.ObjectCount)
assert.Zero(t, connector.status.FolderCount)
assert.Zero(t, connector.status.Successful)
connector := loadConnector(ctx, suite.T())
tests := []struct {
name string
getSelector func(t *testing.T) selectors.Selector
}{
{
name: suite.user + " Email",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup()
sel.Include(sel.MailFolders([]string{suite.user}, []string{exchange.DefaultMailFolder}))
streams := make(map[string]<-chan data.Stream)
// Verify Items() call returns an iterable channel(e.g. a channel that has been closed)
for _, collection := range collectionList {
temp := collection.Items()
testName := collection.FullPath().ResourceOwner()
streams[testName] = temp
return sel.Selector
},
},
{
name: suite.user + " Contacts",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup()
sel.Include(sel.ContactFolders([]string{suite.user}, []string{exchange.DefaultContactFolder}))
return sel.Selector
},
},
{
name: suite.user + " Events",
getSelector: func(t *testing.T) selectors.Selector {
sel := selectors.NewExchangeBackup()
sel.Include(sel.EventCalendars([]string{suite.user}, []string{exchange.DefaultCalendar}))
return sel.Selector
},
},
}
status := connector.AwaitStatus()
assert.NotZero(t, status.Successful)
for name, channel := range streams {
suite.T().Run(name, func(t *testing.T) {
t.Logf("Test: %s\t Items: %d", name, len(channel))
for _, test := range tests {
suite.T().Run(test.name, func(t *testing.T) {
collection, err := connector.ExchangeDataCollection(ctx, test.getSelector(t))
require.NoError(t, err)
assert.Equal(t, len(collection), 1)
channel := collection[0].Items()
for object := range channel {
buf := &bytes.Buffer{}
_, err := buf.ReadFrom(object.ToReader())
assert.NoError(t, err, "received a buf.Read error")
}
status := connector.AwaitStatus()
assert.NotZero(t, status.Successful)
t.Log(status.String())
})
}
}
@ -127,7 +143,7 @@ func (suite *GraphConnectorIntegrationSuite) TestMailSerializationRegression() {
t := suite.T()
connector := loadConnector(ctx, t)
sel := selectors.NewExchangeBackup()
sel.Include(sel.MailFolders([]string{suite.user}, []string{"Inbox"}))
sel.Include(sel.MailFolders([]string{suite.user}, []string{exchange.DefaultMailFolder}))
eb, err := sel.ToExchangeBackup()
require.NoError(t, err)
@ -162,27 +178,40 @@ func (suite *GraphConnectorIntegrationSuite) TestMailSerializationRegression() {
// and to store contact within Collection. Downloaded contacts are run through
// a regression test to ensure that downloaded items can be uploaded.
func (suite *GraphConnectorIntegrationSuite) TestContactSerializationRegression() {
ctx := context.Background()
t := suite.T()
sel := selectors.NewExchangeBackup()
sel.Include(sel.ContactFolders([]string{suite.user}, selectors.Any()))
eb, err := sel.ToExchangeBackup()
require.NoError(t, err)
connector := loadConnector(context.Background(), suite.T())
scopes := eb.Scopes()
connector := loadConnector(ctx, t)
tests := []struct {
name string
getCollection func(t *testing.T) []*exchange.Collection
}{
{
name: "Default Contact Folder",
getCollection: func(t *testing.T) []*exchange.Collection {
sel := selectors.NewExchangeBackup()
sel.Include(sel.ContactFolders([]string{suite.user}, []string{exchange.DefaultContactFolder}))
eb, err := sel.ToExchangeBackup()
require.NoError(t, err)
suite.Len(scopes, 1)
contactsOnly := scopes[0]
collections, err := connector.createCollections(context.Background(), contactsOnly)
assert.NoError(t, err)
scopes := eb.Scopes()
number := 0
suite.Len(scopes, 1)
contactsOnly := scopes[0]
collections, err := connector.createCollections(context.Background(), contactsOnly)
require.NoError(t, err)
for _, edc := range collections {
testName := fmt.Sprintf("%s_ContactFolder_%d", edc.FullPath().ResourceOwner(), number)
suite.T().Run(testName, func(t *testing.T) {
return collections
},
},
}
for _, test := range tests {
suite.T().Run(test.name, func(t *testing.T) {
edcs := test.getCollection(t)
assert.Equal(t, len(edcs), 1)
edc := edcs[0]
assert.Equal(t, edc.FullPath().Folder(), exchange.DefaultContactFolder)
streamChannel := edc.Items()
count := 0
for stream := range streamChannel {
buf := &bytes.Buffer{}
read, err := buf.ReadFrom(stream.ToReader())
@ -190,52 +219,80 @@ func (suite *GraphConnectorIntegrationSuite) TestContactSerializationRegression(
assert.NotZero(t, read)
contact, err := support.CreateContactFromBytes(buf.Bytes())
assert.NotNil(t, contact)
assert.NoError(t, err)
assert.NoError(t, err, "error on converting contact bytes: "+string(buf.Bytes()))
count++
}
number++
assert.NotZero(t, count)
status := connector.AwaitStatus()
suite.NotNil(status)
suite.Equal(status.ObjectCount, status.Successful)
})
}
status := connector.AwaitStatus()
suite.NotNil(status)
suite.Equal(status.ObjectCount, status.Successful)
}
// TestEventsSerializationRegression ensures functionality of createCollections
// to be able to successfully query, download and restore event objects
func (suite *GraphConnectorIntegrationSuite) TestEventsSerializationRegression() {
ctx := context.Background()
t := suite.T()
connector := loadConnector(ctx, t)
sel := selectors.NewExchangeBackup()
sel.Include(sel.EventCalendars([]string{suite.user}, selectors.Any()))
scopes := sel.Scopes()
suite.Equal(len(scopes), 1)
collections, err := connector.createCollections(context.Background(), scopes[0])
require.NoError(t, err)
connector := loadConnector(context.Background(), suite.T())
for _, edc := range collections {
streamChannel := edc.Items()
number := 0
tests := []struct {
name, expected string
getCollection func(t *testing.T) []*exchange.Collection
}{
{
name: "Default Event Calendar",
expected: exchange.DefaultCalendar,
getCollection: func(t *testing.T) []*exchange.Collection {
sel := selectors.NewExchangeBackup()
sel.Include(sel.EventCalendars([]string{suite.user}, []string{exchange.DefaultCalendar}))
scopes := sel.Scopes()
suite.Equal(len(scopes), 1)
collections, err := connector.createCollections(context.Background(), scopes[0])
require.NoError(t, err)
for stream := range streamChannel {
testName := fmt.Sprintf("%s_Event_%d", edc.FullPath().ResourceOwner(), number)
suite.T().Run(testName, func(t *testing.T) {
return collections
},
},
{
name: "Birthday Calendar",
expected: "Birthdays",
getCollection: func(t *testing.T) []*exchange.Collection {
sel := selectors.NewExchangeBackup()
sel.Include(sel.EventCalendars([]string{suite.user}, []string{"Birthdays"}))
scopes := sel.Scopes()
suite.Equal(len(scopes), 1)
collections, err := connector.createCollections(context.Background(), scopes[0])
require.NoError(t, err)
return collections
},
},
}
for _, test := range tests {
suite.T().Run(test.name, func(t *testing.T) {
collections := test.getCollection(t)
require.Equal(t, len(collections), 1)
edc := collections[0]
assert.Equal(t, edc.FullPath().Folder(), test.expected)
streamChannel := edc.Items()
for stream := range streamChannel {
buf := &bytes.Buffer{}
read, err := buf.ReadFrom(stream.ToReader())
assert.NoError(t, err)
assert.NotZero(t, read)
event, err := support.CreateEventFromBytes(buf.Bytes())
assert.NotNil(t, event)
assert.NoError(t, err)
})
}
}
assert.NoError(t, err, "experienced error parsing event bytes: "+string(buf.Bytes()))
}
status := connector.AwaitStatus()
suite.NotNil(status)
suite.Equal(status.ObjectCount, status.Successful)
status := connector.AwaitStatus()
suite.NotNil(status)
suite.Equal(status.ObjectCount, status.Successful)
})
}
}
// TestAccessOfInboxAllUsers verifies that GraphConnector can
@ -249,7 +306,7 @@ func (suite *GraphConnectorIntegrationSuite) TestAccessOfInboxAllUsers() {
t := suite.T()
connector := loadConnector(ctx, t)
sel := selectors.NewExchangeBackup()
sel.Include(sel.MailFolders(selectors.Any(), []string{"Inbox"}))
sel.Include(sel.MailFolders(selectors.Any(), []string{exchange.DefaultMailFolder}))
scopes := sel.DiscreteScopes(connector.GetUsers())
for _, scope := range scopes {

View File

@ -102,7 +102,6 @@ func (suite *ItemIntegrationSuite) TestItemReader() {
)
// Read data for the file
name, itemData, err := driveItemReader(ctx, suite, driveID, driveItemID)
require.NoError(suite.T(), err)
require.NotEmpty(suite.T(), name)