extract container transforms from the api layer (#4478)
removes the cache container transformation funcs from the exchange api container enumeration params. This ensures a cleaner separation of ownership where the api is only responsible for enumerating containers, and the caller is responsible for transforming them. --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [ ] 🧹 Tech Debt/Cleanup #### Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
89f59eea91
commit
7f8becb8f8
@ -21,9 +21,6 @@ import (
|
||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||
)
|
||||
|
||||
// CreateCollections - utility function that retrieves M365
|
||||
// IDs through Microsoft Graph API. The selectors.ExchangeScope
|
||||
// determines the type of collections that are retrieved.
|
||||
func CreateCollections(
|
||||
ctx context.Context,
|
||||
bpc inject.BackupProducerConfig,
|
||||
|
||||
@ -796,53 +796,25 @@ func (suite *BackupIntgSuite) TestContactSerializationRegression() {
|
||||
// TestEventsSerializationRegression ensures functionality of createCollections
|
||||
// to be able to successfully query, download and restore event objects
|
||||
func (suite *BackupIntgSuite) TestEventsSerializationRegression() {
|
||||
t := suite.T()
|
||||
|
||||
ctx, flush := tester.NewContext(t)
|
||||
defer flush()
|
||||
|
||||
var (
|
||||
users = []string{suite.user}
|
||||
handlers = BackupHandlers(suite.ac)
|
||||
calID string
|
||||
bdayID string
|
||||
)
|
||||
|
||||
fn := func(gcc graph.CachedContainer) error {
|
||||
if ptr.Val(gcc.GetDisplayName()) == api.DefaultCalendar {
|
||||
calID = ptr.Val(gcc.GetId())
|
||||
}
|
||||
|
||||
if ptr.Val(gcc.GetDisplayName()) == "Birthdays" {
|
||||
bdayID = ptr.Val(gcc.GetId())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err := suite.ac.Events().EnumerateContainers(
|
||||
ctx,
|
||||
suite.user,
|
||||
"",
|
||||
false,
|
||||
fn,
|
||||
fault.New(true))
|
||||
require.NoError(t, err, clues.ToCore(err))
|
||||
|
||||
tests := []struct {
|
||||
name, expected string
|
||||
scope selectors.ExchangeScope
|
||||
name, expectedContainerName string
|
||||
scope selectors.ExchangeScope
|
||||
}{
|
||||
{
|
||||
name: "Default Event Calendar",
|
||||
expected: calID,
|
||||
name: "Default Event Calendar",
|
||||
expectedContainerName: api.DefaultCalendar,
|
||||
scope: selectors.NewExchangeBackup(users).EventCalendars(
|
||||
[]string{api.DefaultCalendar},
|
||||
selectors.PrefixMatch())[0],
|
||||
},
|
||||
{
|
||||
name: "Birthday Calendar",
|
||||
expected: bdayID,
|
||||
name: "Birthday Calendar",
|
||||
expectedContainerName: "Birthdays",
|
||||
scope: selectors.NewExchangeBackup(users).EventCalendars(
|
||||
[]string{"Birthdays"},
|
||||
selectors.PrefixMatch())[0],
|
||||
@ -879,13 +851,16 @@ func (suite *BackupIntgSuite) TestEventsSerializationRegression() {
|
||||
wg.Add(len(collections))
|
||||
|
||||
for _, edc := range collections {
|
||||
dlp, isDLP := edc.(data.LocationPather)
|
||||
|
||||
var isMetadata bool
|
||||
|
||||
if edc.FullPath().Service() != path.ExchangeMetadataService {
|
||||
isMetadata = true
|
||||
assert.Equal(t, test.expected, edc.FullPath().Folder(false))
|
||||
if edc.FullPath().Service() == path.ExchangeService {
|
||||
require.True(t, isDLP, "must be a location pather")
|
||||
assert.Contains(t, dlp.LocationPath().Elements(), test.expectedContainerName)
|
||||
} else {
|
||||
assert.Equal(t, "", edc.FullPath().Folder(false))
|
||||
isMetadata = true
|
||||
assert.Empty(t, edc.FullPath().Folder(false))
|
||||
}
|
||||
|
||||
for item := range edc.Items(ctx, fault.New(true)) {
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/alcionai/clues"
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||
@ -37,11 +38,30 @@ func (r *contactRefresher) refreshContainer(
|
||||
|
||||
type contactContainerCache struct {
|
||||
*containerResolver
|
||||
enumer containersEnumerator
|
||||
enumer containersEnumerator[models.ContactFolderable]
|
||||
getter containerGetter
|
||||
userID string
|
||||
}
|
||||
|
||||
func (cfc *contactContainerCache) init(
|
||||
ctx context.Context,
|
||||
baseNode string,
|
||||
baseContainerPath []string,
|
||||
) error {
|
||||
if len(baseNode) == 0 {
|
||||
return clues.New("m365 folderID required for base contact folder").WithClues(ctx)
|
||||
}
|
||||
|
||||
if cfc.containerResolver == nil {
|
||||
cfc.containerResolver = newContainerResolver(&contactRefresher{
|
||||
userID: cfc.userID,
|
||||
getter: cfc.getter,
|
||||
})
|
||||
}
|
||||
|
||||
return cfc.populateContactRoot(ctx, baseNode, baseContainerPath)
|
||||
}
|
||||
|
||||
func (cfc *contactContainerCache) populateContactRoot(
|
||||
ctx context.Context,
|
||||
directoryID string,
|
||||
@ -77,39 +97,35 @@ func (cfc *contactContainerCache) Populate(
|
||||
return clues.Wrap(err, "initializing")
|
||||
}
|
||||
|
||||
err := cfc.enumer.EnumerateContainers(
|
||||
el := errs.Local()
|
||||
|
||||
containers, err := cfc.enumer.EnumerateContainers(
|
||||
ctx,
|
||||
cfc.userID,
|
||||
baseID,
|
||||
false,
|
||||
cfc.addFolder,
|
||||
errs)
|
||||
false)
|
||||
if err != nil {
|
||||
return clues.Wrap(err, "enumerating containers")
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
if el.Failure() != nil {
|
||||
return el.Failure()
|
||||
}
|
||||
|
||||
cacheFolder := graph.NewCacheFolder(c, nil, nil)
|
||||
|
||||
err := cfc.addFolder(&cacheFolder)
|
||||
if err != nil {
|
||||
errs.AddRecoverable(
|
||||
ctx,
|
||||
graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||
}
|
||||
}
|
||||
|
||||
if err := cfc.populatePaths(ctx, errs); err != nil {
|
||||
return clues.Wrap(err, "populating paths")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfc *contactContainerCache) init(
|
||||
ctx context.Context,
|
||||
baseNode string,
|
||||
baseContainerPath []string,
|
||||
) error {
|
||||
if len(baseNode) == 0 {
|
||||
return clues.New("m365 folderID required for base contact folder").WithClues(ctx)
|
||||
}
|
||||
|
||||
if cfc.containerResolver == nil {
|
||||
cfc.containerResolver = newContainerResolver(&contactRefresher{
|
||||
userID: cfc.userID,
|
||||
getter: cfc.getter,
|
||||
})
|
||||
}
|
||||
|
||||
return cfc.populateContactRoot(ctx, baseNode, baseContainerPath)
|
||||
return el.Failure()
|
||||
}
|
||||
|
||||
@ -23,14 +23,12 @@ type containerGetter interface {
|
||||
) (graph.Container, error)
|
||||
}
|
||||
|
||||
type containersEnumerator interface {
|
||||
type containersEnumerator[T any] interface {
|
||||
EnumerateContainers(
|
||||
ctx context.Context,
|
||||
userID, baseDirID string,
|
||||
immutableIDs bool,
|
||||
fn func(graph.CachedContainer) error,
|
||||
errs *fault.Bus,
|
||||
) error
|
||||
) ([]T, error)
|
||||
}
|
||||
|
||||
type containerRefresher interface {
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/alcionai/clues"
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||
@ -16,7 +17,7 @@ var _ graph.ContainerResolver = &eventContainerCache{}
|
||||
|
||||
type eventContainerCache struct {
|
||||
*containerResolver
|
||||
enumer containersEnumerator
|
||||
enumer containersEnumerator[models.Calendarable]
|
||||
getter containerGetter
|
||||
userID string
|
||||
}
|
||||
@ -70,22 +71,40 @@ func (ecc *eventContainerCache) Populate(
|
||||
return clues.Wrap(err, "initializing")
|
||||
}
|
||||
|
||||
err := ecc.enumer.EnumerateContainers(
|
||||
el := errs.Local()
|
||||
|
||||
containers, err := ecc.enumer.EnumerateContainers(
|
||||
ctx,
|
||||
ecc.userID,
|
||||
"",
|
||||
false,
|
||||
ecc.addFolder,
|
||||
errs)
|
||||
false)
|
||||
if err != nil {
|
||||
return clues.Wrap(err, "enumerating containers")
|
||||
}
|
||||
|
||||
if err := ecc.populatePaths(ctx, errs); err != nil {
|
||||
return clues.Wrap(err, "establishing calendar paths")
|
||||
for _, c := range containers {
|
||||
if el.Failure() != nil {
|
||||
return el.Failure()
|
||||
}
|
||||
|
||||
cacheFolder := graph.NewCacheFolder(
|
||||
api.CalendarDisplayable{Calendarable: c},
|
||||
path.Builder{}.Append(ptr.Val(c.GetId())),
|
||||
path.Builder{}.Append(ptr.Val(c.GetName())))
|
||||
|
||||
err := ecc.addFolder(&cacheFolder)
|
||||
if err != nil {
|
||||
errs.AddRecoverable(
|
||||
ctx,
|
||||
graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
if err := ecc.populatePaths(ctx, errs); err != nil {
|
||||
return clues.Wrap(err, "populating paths")
|
||||
}
|
||||
|
||||
return el.Failure()
|
||||
}
|
||||
|
||||
// AddToCache adds container to map in field 'cache'
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/alcionai/clues"
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||
"github.com/alcionai/corso/src/pkg/fault"
|
||||
@ -40,7 +41,7 @@ func (r *mailRefresher) refreshContainer(
|
||||
// nameLookup map: Key: DisplayName Value: ID
|
||||
type mailContainerCache struct {
|
||||
*containerResolver
|
||||
enumer containersEnumerator
|
||||
enumer containersEnumerator[models.MailFolderable]
|
||||
getter containerGetter
|
||||
userID string
|
||||
}
|
||||
@ -100,20 +101,35 @@ func (mc *mailContainerCache) Populate(
|
||||
return clues.Wrap(err, "initializing")
|
||||
}
|
||||
|
||||
err := mc.enumer.EnumerateContainers(
|
||||
el := errs.Local()
|
||||
|
||||
containers, err := mc.enumer.EnumerateContainers(
|
||||
ctx,
|
||||
mc.userID,
|
||||
"",
|
||||
false,
|
||||
mc.addFolder,
|
||||
errs)
|
||||
false)
|
||||
if err != nil {
|
||||
return clues.Wrap(err, "enumerating containers")
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
if el.Failure() != nil {
|
||||
return el.Failure()
|
||||
}
|
||||
|
||||
cacheFolder := graph.NewCacheFolder(c, nil, nil)
|
||||
|
||||
err := mc.addFolder(&cacheFolder)
|
||||
if err != nil {
|
||||
errs.AddRecoverable(
|
||||
ctx,
|
||||
graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||
}
|
||||
}
|
||||
|
||||
if err := mc.populatePaths(ctx, errs); err != nil {
|
||||
return clues.Wrap(err, "populating paths")
|
||||
}
|
||||
|
||||
return nil
|
||||
return el.Failure()
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||
"github.com/alcionai/corso/src/pkg/fault"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
)
|
||||
|
||||
@ -67,42 +66,14 @@ func (p *contactsFoldersPageCtrl) ValidModTimes() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// EnumerateContainers iterates through all of the users current
|
||||
// contacts folders, transforming each to a graph.CacheFolder, and calling
|
||||
// fn(cf).
|
||||
// Contact folders are represented in their current state, and do
|
||||
// not contain historical data.
|
||||
// EnumerateContainers retrieves all of the user's current contact folders.
|
||||
func (c Contacts) EnumerateContainers(
|
||||
ctx context.Context,
|
||||
userID, baseContainerID string,
|
||||
immutableIDs bool,
|
||||
fn func(graph.CachedContainer) error,
|
||||
errs *fault.Bus,
|
||||
) error {
|
||||
var (
|
||||
el = errs.Local()
|
||||
pgr = c.NewContactFoldersPager(userID, baseContainerID, immutableIDs)
|
||||
)
|
||||
|
||||
containers, err := batchEnumerateItems(ctx, pgr)
|
||||
if err != nil {
|
||||
return graph.Stack(ctx, err)
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
if el.Failure() != nil {
|
||||
break
|
||||
}
|
||||
|
||||
gncf := graph.NewCacheFolder(c, nil, nil)
|
||||
|
||||
if err := fn(&gncf); err != nil {
|
||||
errs.AddRecoverable(ctx, graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return el.Failure()
|
||||
) ([]models.ContactFolderable, error) {
|
||||
containers, err := batchEnumerateItems(ctx, c.NewContactFoldersPager(userID, baseContainerID, immutableIDs))
|
||||
return containers, graph.Stack(ctx, err).OrNil()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||
"github.com/alcionai/corso/src/pkg/fault"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
)
|
||||
|
||||
@ -68,45 +67,14 @@ func (p *eventsCalendarsPageCtrl) ValidModTimes() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// EnumerateContainers iterates through all of the users current
|
||||
// events calendars, transforming each to a graph.CacheFolder, and calling
|
||||
// fn(cf).
|
||||
// Calendars are represented in their current state, and do
|
||||
// not contain historical data.
|
||||
// EnumerateContainers retrieves all of the user's current mail folders.
|
||||
func (c Events) EnumerateContainers(
|
||||
ctx context.Context,
|
||||
userID, _ string, // baseContainerID not needed
|
||||
userID, _ string, // baseContainerID not needed here
|
||||
immutableIDs bool,
|
||||
fn func(graph.CachedContainer) error,
|
||||
errs *fault.Bus,
|
||||
) error {
|
||||
var (
|
||||
el = errs.Local()
|
||||
pgr = c.NewEventCalendarsPager(userID, immutableIDs)
|
||||
)
|
||||
|
||||
containers, err := batchEnumerateItems(ctx, pgr)
|
||||
if err != nil {
|
||||
return graph.Stack(ctx, err)
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
if el.Failure() != nil {
|
||||
break
|
||||
}
|
||||
|
||||
gncf := graph.NewCacheFolder(
|
||||
CalendarDisplayable{Calendarable: c},
|
||||
path.Builder{}.Append(ptr.Val(c.GetId())),
|
||||
path.Builder{}.Append(ptr.Val(c.GetName())))
|
||||
|
||||
if err := fn(&gncf); err != nil {
|
||||
errs.AddRecoverable(ctx, graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return el.Failure()
|
||||
) ([]models.Calendarable, error) {
|
||||
containers, err := batchEnumerateItems(ctx, c.NewEventCalendarsPager(userID, immutableIDs))
|
||||
return containers, graph.Stack(ctx, err).OrNil()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@ -13,13 +13,11 @@ import (
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/dttm"
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||
exchMock "github.com/alcionai/corso/src/internal/m365/service/exchange/mock"
|
||||
"github.com/alcionai/corso/src/internal/tester"
|
||||
"github.com/alcionai/corso/src/internal/tester/tconfig"
|
||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||
"github.com/alcionai/corso/src/pkg/control/testdata"
|
||||
"github.com/alcionai/corso/src/pkg/fault"
|
||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||
)
|
||||
|
||||
@ -294,8 +292,8 @@ func (suite *EventsAPIIntgSuite) TestEvents_canFindNonStandardFolder() {
|
||||
var (
|
||||
found bool
|
||||
calID = ptr.Val(cal.GetId())
|
||||
findContainer = func(gcc graph.CachedContainer) error {
|
||||
if ptr.Val(gcc.GetId()) == calID {
|
||||
findContainer = func(mc models.Calendarable) error {
|
||||
if ptr.Val(mc.GetId()) == calID {
|
||||
found = true
|
||||
}
|
||||
|
||||
@ -303,14 +301,18 @@ func (suite *EventsAPIIntgSuite) TestEvents_canFindNonStandardFolder() {
|
||||
}
|
||||
)
|
||||
|
||||
err = ac.EnumerateContainers(
|
||||
containers, err := ac.EnumerateContainers(
|
||||
ctx,
|
||||
suite.its.user.id,
|
||||
api.DefaultCalendar,
|
||||
false,
|
||||
findContainer,
|
||||
fault.New(true))
|
||||
false)
|
||||
require.NoError(t, err, clues.ToCore(err))
|
||||
|
||||
for _, c := range containers {
|
||||
err := findContainer(c)
|
||||
require.NoError(t, err, clues.ToCore(err))
|
||||
}
|
||||
|
||||
require.True(
|
||||
t,
|
||||
found,
|
||||
|
||||
@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/m365/graph"
|
||||
"github.com/alcionai/corso/src/pkg/fault"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
)
|
||||
|
||||
@ -64,42 +63,14 @@ func (p *mailFoldersPageCtrl) ValidModTimes() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// EnumerateContainers iterates through all of the users current
|
||||
// mail folders, transforming each to a graph.CacheFolder, and calling
|
||||
// fn(cf).
|
||||
// Folder hierarchy is represented in its current state, and does
|
||||
// not contain historical data.
|
||||
// EnumerateContainers retrieves all of the user's current mail folders.
|
||||
func (c Mail) EnumerateContainers(
|
||||
ctx context.Context,
|
||||
userID, _ string, // baseContainerID not needed here
|
||||
immutableIDs bool,
|
||||
fn func(graph.CachedContainer) error,
|
||||
errs *fault.Bus,
|
||||
) error {
|
||||
var (
|
||||
el = errs.Local()
|
||||
pgr = c.NewMailFoldersPager(userID, immutableIDs)
|
||||
)
|
||||
|
||||
containers, err := batchEnumerateItems(ctx, pgr)
|
||||
if err != nil {
|
||||
return graph.Stack(ctx, err)
|
||||
}
|
||||
|
||||
for _, c := range containers {
|
||||
if el.Failure() != nil {
|
||||
break
|
||||
}
|
||||
|
||||
gncf := graph.NewCacheFolder(c, nil, nil)
|
||||
|
||||
if err := fn(&gncf); err != nil {
|
||||
errs.AddRecoverable(ctx, graph.Stack(ctx, err).Label(fault.LabelForceNoBackupCreation))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return el.Failure()
|
||||
) ([]models.MailFolderable, error) {
|
||||
containers, err := batchEnumerateItems(ctx, c.NewMailFoldersPager(userID, immutableIDs))
|
||||
return containers, graph.Stack(ctx, err).OrNil()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user