From 4c452bcd8ea9153410e13b0624d4692885afb321 Mon Sep 17 00:00:00 2001 From: Keepers Date: Wed, 30 Aug 2023 11:21:53 -0600 Subject: [PATCH] add channel and messages enumerators (#4135) adds enumerators for channels, and a delta of channel messages. Also updates the its struct to include group ids, and reformats some of the struct schema. --- #### Does this PR need a docs update or release note? - [x] :no_entry: No #### Type of change - [x] :sunflower: Feature #### Issue(s) * #3989 #### Test Plan - [x] :zap: Unit test - [x] :green_heart: E2E --- src/internal/m365/collection/groups/backup.go | 2 +- .../m365/collection/groups/handlers.go | 6 +- src/pkg/services/m365/api/channels_pager.go | 227 ++++++++++++++++-- .../services/m365/api/channels_pager_test.go | 78 +++--- .../services/m365/api/contacts_pager_test.go | 12 +- src/pkg/services/m365/api/contacts_test.go | 4 +- src/pkg/services/m365/api/drive_pager_test.go | 20 +- src/pkg/services/m365/api/drive_test.go | 20 +- .../services/m365/api/events_pager_test.go | 6 +- src/pkg/services/m365/api/events_test.go | 6 +- src/pkg/services/m365/api/groups_test.go | 2 +- src/pkg/services/m365/api/helper_test.go | 56 +++-- src/pkg/services/m365/api/lists_test.go | 2 +- src/pkg/services/m365/api/mail_pager_test.go | 10 +- src/pkg/services/m365/api/mail_test.go | 8 +- src/pkg/services/m365/api/users_test.go | 4 +- 16 files changed, 329 insertions(+), 134 deletions(-) diff --git a/src/internal/m365/collection/groups/backup.go b/src/internal/m365/collection/groups/backup.go index 9b31126a1..4624dd942 100644 --- a/src/internal/m365/collection/groups/backup.go +++ b/src/internal/m365/collection/groups/backup.go @@ -243,7 +243,7 @@ func populateCollections( func collectItems( ctx context.Context, - pager api.ChannelMessageDeltaEnumerator, + pager api.DeltaPager[models.ChatMessageable], ) ([]models.ChatMessageable, error) { items := []models.ChatMessageable{} diff --git a/src/internal/m365/collection/groups/handlers.go b/src/internal/m365/collection/groups/handlers.go index bf3cb8f0f..120b167d9 100644 --- a/src/internal/m365/collection/groups/handlers.go +++ b/src/internal/m365/collection/groups/handlers.go @@ -16,7 +16,7 @@ type BackupHandler interface { ) (models.Channelable, error) NewChannelsPager( teamID string, - ) api.ChannelDeltaEnumerator + ) api.Pager[models.Channelable] GetMessageByID( ctx context.Context, @@ -24,7 +24,7 @@ type BackupHandler interface { ) (models.ChatMessageable, error) NewMessagePager( teamID, channelID string, - ) api.ChannelMessageDeltaEnumerator + ) api.DeltaPager[models.ChatMessageable] GetMessageReplies( ctx context.Context, @@ -34,7 +34,7 @@ type BackupHandler interface { type BackupMessagesHandler interface { GetMessage(ctx context.Context, teamID, channelID, itemID string) (models.ChatMessageable, error) - NewMessagePager(teamID, channelID string) api.ChannelMessageDeltaEnumerator + NewMessagePager(teamID, channelID string) api.DeltaPager[models.ChatMessageable] GetChannel(ctx context.Context, teamID, channelID string) (models.Channelable, error) GetReply(ctx context.Context, teamID, channelID, messageID string) (serialization.Parsable, error) } diff --git a/src/pkg/services/m365/api/channels_pager.go b/src/pkg/services/m365/api/channels_pager.go index 58aecaf6c..f7b7ccc43 100644 --- a/src/pkg/services/m365/api/channels_pager.go +++ b/src/pkg/services/m365/api/channels_pager.go @@ -1,43 +1,224 @@ package api import ( + "context" + "github.com/microsoftgraph/msgraph-sdk-go/models" + "github.com/microsoftgraph/msgraph-sdk-go/teams" + + "github.com/alcionai/corso/src/internal/common/ptr" + "github.com/alcionai/corso/src/internal/m365/graph" + "github.com/alcionai/corso/src/pkg/logger" ) // --------------------------------------------------------------------------- -// item pager +// channel message pager // --------------------------------------------------------------------------- -type ChannelMessageDeltaEnumerator interface { - DeltaGetPager - ValuesInPageLinker[models.ChatMessageable] - SetNextLinker +var _ DeltaPager[models.ChatMessageable] = &channelMessageDeltaPageCtrl{} + +type channelMessageDeltaPageCtrl struct { + resourceID, channelID string + gs graph.Servicer + builder *teams.ItemChannelsItemMessagesDeltaRequestBuilder + options *teams.ItemChannelsItemMessagesDeltaRequestBuilderGetRequestConfiguration } -// TODO: implement -// var _ ChannelMessageDeltaEnumerator = &messagePageCtrl{} +func (p *channelMessageDeltaPageCtrl) SetNext(nextLink string) { + p.builder = teams.NewItemChannelsItemMessagesDeltaRequestBuilder(nextLink, p.gs.Adapter()) +} -// type messagePageCtrl struct { -// gs graph.Servicer -// builder *teams.ItemChannelsItemMessagesRequestBuilder -// options *teams.ItemChannelsItemMessagesRequestBuilderGetRequestConfiguration -// } +func (p *channelMessageDeltaPageCtrl) GetPage( + ctx context.Context, +) (DeltaPageLinker, error) { + resp, err := p.builder.Get(ctx, p.options) + return resp, graph.Stack(ctx, err).OrNil() +} + +func (p *channelMessageDeltaPageCtrl) Reset(context.Context) { + p.builder = p.gs. + Client(). + Teams(). + ByTeamId(p.resourceID). + Channels(). + ByChannelId(p.channelID). + Messages(). + Delta() +} + +func (p *channelMessageDeltaPageCtrl) ValuesIn(l PageLinker) ([]models.ChatMessageable, error) { + return getValues[models.ChatMessageable](l) +} + +func (c Channels) NewChannelMessageDeltaPager( + teamID, channelID, prevDelta string, +) *channelMessageDeltaPageCtrl { + builder := c.Stable. + Client(). + Teams(). + ByTeamId(teamID). + Channels(). + ByChannelId(channelID). + Messages(). + Delta() + + if len(prevDelta) > 0 { + builder = teams.NewItemChannelsItemMessagesDeltaRequestBuilder(prevDelta, c.Stable.Adapter()) + } + + options := &teams.ItemChannelsItemMessagesDeltaRequestBuilderGetRequestConfiguration{ + Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize)), + } + + return &channelMessageDeltaPageCtrl{ + resourceID: teamID, + channelID: channelID, + builder: builder, + gs: c.Stable, + options: options, + } +} + +// GetChannelMessagesDelta fetches a delta of all messages in the channel. +func (c Channels) GetChannelMessagesDelta( + ctx context.Context, + teamID, channelID, prevDelta string, +) ([]models.ChatMessageable, DeltaUpdate, error) { + var ( + vs = []models.ChatMessageable{} + pager = c.NewChannelMessageDeltaPager(teamID, channelID, prevDelta) + invalidPrevDelta = len(prevDelta) == 0 + newDeltaLink string + ) + + // Loop through all pages returned by Graph API. + for { + page, err := pager.GetPage(graph.ConsumeNTokens(ctx, graph.SingleGetOrDeltaLC)) + if graph.IsErrInvalidDelta(err) { + logger.Ctx(ctx).Infow("Invalid previous delta", "delta_link", prevDelta) + + invalidPrevDelta = true + vs = []models.ChatMessageable{} + + pager.Reset(ctx) + + continue + } + + if err != nil { + return nil, DeltaUpdate{}, graph.Wrap(ctx, err, "retrieving page of channel messages") + } + + vals, err := pager.ValuesIn(page) + if err != nil { + return nil, DeltaUpdate{}, graph.Wrap(ctx, err, "extracting channel messages from response") + } + + vs = append(vs, vals...) + + nextLink, deltaLink := NextAndDeltaLink(page) + + if len(deltaLink) > 0 { + newDeltaLink = deltaLink + } + + if len(nextLink) == 0 { + break + } + + pager.SetNext(nextLink) + } + + logger.Ctx(ctx).Debugf("retrieved %d channel messages", len(vs)) + + du := DeltaUpdate{ + URL: newDeltaLink, + Reset: invalidPrevDelta, + } + + return vs, du, nil +} // --------------------------------------------------------------------------- // channel pager // --------------------------------------------------------------------------- -type ChannelDeltaEnumerator interface { - DeltaGetPager - ValuesInPageLinker[models.Channelable] - SetNextLinker +var _ Pager[models.Channelable] = &channelPageCtrl{} + +type channelPageCtrl struct { + gs graph.Servicer + builder *teams.ItemChannelsRequestBuilder + options *teams.ItemChannelsRequestBuilderGetRequestConfiguration } -// TODO: implement -// var _ ChannelDeltaEnumerator = &channelsPageCtrl{} +func (p *channelPageCtrl) SetNext(nextLink string) { + p.builder = teams.NewItemChannelsRequestBuilder(nextLink, p.gs.Adapter()) +} -// type channelsPageCtrl struct { -// gs graph.Servicer -// builder *teams.ItemChannelsChannelItemRequestBuilder -// options *teams.ItemChannelsChannelItemRequestBuilderGetRequestConfiguration -// } +func (p *channelPageCtrl) GetPage( + ctx context.Context, +) (PageLinker, error) { + resp, err := p.builder.Get(ctx, p.options) + return resp, graph.Stack(ctx, err).OrNil() +} + +func (p *channelPageCtrl) ValuesIn(l PageLinker) ([]models.Channelable, error) { + return getValues[models.Channelable](l) +} + +func (c Channels) NewChannelPager( + teamID string, +) *channelPageCtrl { + requestConfig := &teams.ItemChannelsRequestBuilderGetRequestConfiguration{ + Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize)), + } + + res := &channelPageCtrl{ + gs: c.Stable, + options: requestConfig, + builder: c.Stable. + Client(). + Teams(). + ByTeamId(teamID). + Channels(), + } + + return res +} + +// GetChannels fetches all channels in the team. +func (c Channels) GetChannels( + ctx context.Context, + teamID string, +) ([]models.Channelable, error) { + var ( + vs = []models.Channelable{} + pager = c.NewChannelPager(teamID) + ) + + // Loop through all pages returned by Graph API. + for { + page, err := pager.GetPage(ctx) + if err != nil { + return nil, graph.Wrap(ctx, err, "retrieving page of channels") + } + + vals, err := pager.ValuesIn(page) + if err != nil { + return nil, graph.Wrap(ctx, err, "extracting channels from response") + } + + vs = append(vs, vals...) + + nextLink := ptr.Val(page.GetOdataNextLink()) + if len(nextLink) == 0 { + break + } + + pager.SetNext(nextLink) + } + + logger.Ctx(ctx).Debugf("retrieved %d channels", len(vs)) + + return vs, nil +} diff --git a/src/pkg/services/m365/api/channels_pager_test.go b/src/pkg/services/m365/api/channels_pager_test.go index 615e96ebe..2e78a1787 100644 --- a/src/pkg/services/m365/api/channels_pager_test.go +++ b/src/pkg/services/m365/api/channels_pager_test.go @@ -4,64 +4,70 @@ import ( "testing" "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/common/ptr" "github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/internal/tester/tconfig" ) -type ChannelPagerIntgSuite struct { +type ChannelsPagerIntgSuite struct { tester.Suite its intgTesterSetup } func TestChannelPagerIntgSuite(t *testing.T) { - suite.Run(t, &ChannelPagerIntgSuite{ + suite.Run(t, &ChannelsPagerIntgSuite{ Suite: tester.NewIntegrationSuite( t, [][]string{tconfig.M365AcctCredEnvs}), }) } -func (suite *ChannelPagerIntgSuite) SetupSuite() { +func (suite *ChannelsPagerIntgSuite) SetupSuite() { suite.its = newIntegrationTesterSetup(suite.T()) } -// This will be added once 'pager' is implemented -// func (suite *ChannelPagerIntgSuite) TestChannels_GetPage() { -// t := suite.T() - -// ctx, flush := tester.NewContext(t) -// defer flush() - -// teamID := tconfig.M365TeamID(t) -// channelID := tconfig.M365ChannelID(t) -// pager := suite.its.ac.Channels().NewMessagePager(teamID, channelID, []string{}) -// a, err := pager.GetPage(ctx) -// assert.NoError(t, err, clues.ToCore(err)) -// assert.NotNil(t, a) -// } - -func (suite *ChannelPagerIntgSuite) TestChannels_Get() { - t := suite.T() - ctx, flush := tester.NewContext(t) - - defer flush() - +func (suite *ChannelsPagerIntgSuite) TestEnumerateChannels() { var ( - containerName = "General" - teamID = tconfig.M365TeamID(t) - chanClient = suite.its.ac.Channels() + t = suite.T() + ac = suite.its.ac.Channels() ) - // GET channel -should be found - channel, err := chanClient.GetChannelByName(ctx, teamID, containerName) - assert.NoError(t, err, clues.ToCore(err)) - assert.Equal(t, ptr.Val(channel.GetDisplayName()), containerName) + ctx, flush := tester.NewContext(t) + defer flush() - // GET channel -should be found - _, err = chanClient.GetChannel(ctx, teamID, ptr.Val(channel.GetId())) - assert.NoError(t, err, clues.ToCore(err)) + chans, err := ac.GetChannels(ctx, suite.its.group.id) + require.NoError(t, err, clues.ToCore(err)) + require.NotEmpty(t, chans) +} + +func (suite *ChannelsPagerIntgSuite) TestEnumerateChannelMessages() { + var ( + t = suite.T() + ac = suite.its.ac.Channels() + ) + + ctx, flush := tester.NewContext(t) + defer flush() + + msgs, du, err := ac.GetChannelMessagesDelta( + ctx, + suite.its.group.id, + suite.its.group.testContainerID, + "") + require.NoError(t, err, clues.ToCore(err)) + require.NotEmpty(t, msgs) + require.NotZero(t, du.URL, "delta link") + require.True(t, du.Reset, "reset due to empty prev delta link") + + msgs, du, err = ac.GetChannelMessagesDelta( + ctx, + suite.its.group.id, + suite.its.group.testContainerID, + du.URL) + require.NoError(t, err, clues.ToCore(err)) + require.Empty(t, msgs, "should have no new messages from delta") + require.NotZero(t, du.URL, "delta link") + require.False(t, du.Reset, "prev delta link should be valid") } diff --git a/src/pkg/services/m365/api/contacts_pager_test.go b/src/pkg/services/m365/api/contacts_pager_test.go index 5f3561e6d..5d859cd12 100644 --- a/src/pkg/services/m365/api/contacts_pager_test.go +++ b/src/pkg/services/m365/api/contacts_pager_test.go @@ -39,13 +39,13 @@ func (suite *ContactsPagerIntgSuite) TestContacts_GetItemsInContainerByCollision ctx, flush := tester.NewContext(t) defer flush() - container, err := ac.GetContainerByID(ctx, suite.its.userID, "contacts") + container, err := ac.GetContainerByID(ctx, suite.its.user.id, "contacts") require.NoError(t, err, clues.ToCore(err)) conts, err := ac.Stable. Client(). Users(). - ByUserId(suite.its.userID). + ByUserId(suite.its.user.id). ContactFolders(). ByContactFolderId(ptr.Val(container.GetId())). Contacts(). @@ -61,7 +61,7 @@ func (suite *ContactsPagerIntgSuite) TestContacts_GetItemsInContainerByCollision expect := maps.Keys(expectM) - results, err := suite.its.ac.Contacts().GetItemsInContainerByCollisionKey(ctx, suite.its.userID, "contacts") + results, err := suite.its.ac.Contacts().GetItemsInContainerByCollisionKey(ctx, suite.its.user.id, "contacts") require.NoError(t, err, clues.ToCore(err)) require.Less(t, 0, len(results), "requires at least one result") @@ -91,13 +91,13 @@ func (suite *ContactsPagerIntgSuite) TestContacts_GetItemsIDsInContainer() { ctx, flush := tester.NewContext(t) defer flush() - container, err := ac.GetContainerByID(ctx, suite.its.userID, api.DefaultContacts) + container, err := ac.GetContainerByID(ctx, suite.its.user.id, api.DefaultContacts) require.NoError(t, err, clues.ToCore(err)) msgs, err := ac.Stable. Client(). Users(). - ByUserId(suite.its.userID). + ByUserId(suite.its.user.id). ContactFolders(). ByContactFolderId(ptr.Val(container.GetId())). Contacts(). @@ -112,7 +112,7 @@ func (suite *ContactsPagerIntgSuite) TestContacts_GetItemsIDsInContainer() { } results, err := suite.its.ac.Contacts(). - GetItemIDsInContainer(ctx, suite.its.userID, api.DefaultContacts) + GetItemIDsInContainer(ctx, suite.its.user.id, api.DefaultContacts) require.NoError(t, err, clues.ToCore(err)) require.Less(t, 0, len(results), "requires at least one result") require.Equal(t, len(expect), len(results), "must have same count of items") diff --git a/src/pkg/services/m365/api/contacts_test.go b/src/pkg/services/m365/api/contacts_test.go index afc344cc5..55f059d04 100644 --- a/src/pkg/services/m365/api/contacts_test.go +++ b/src/pkg/services/m365/api/contacts_test.go @@ -141,7 +141,7 @@ func (suite *ContactsAPIIntgSuite) TestContacts_GetContainerByName() { cc, err := suite.its.ac.Contacts().CreateContainer( ctx, - suite.its.userID, + suite.its.user.id, "", rc.Location) require.NoError(t, err, clues.ToCore(err)) @@ -168,7 +168,7 @@ func (suite *ContactsAPIIntgSuite) TestContacts_GetContainerByName() { _, err := suite.its.ac. Contacts(). - GetContainerByName(ctx, suite.its.userID, "", test.name) + GetContainerByName(ctx, suite.its.user.id, "", test.name) test.expectErr(t, err, clues.ToCore(err)) }) } diff --git a/src/pkg/services/m365/api/drive_pager_test.go b/src/pkg/services/m365/api/drive_pager_test.go index 71177e2c8..f28277eee 100644 --- a/src/pkg/services/m365/api/drive_pager_test.go +++ b/src/pkg/services/m365/api/drive_pager_test.go @@ -39,13 +39,13 @@ func (suite *DrivePagerIntgSuite) TestDrives_GetItemsInContainerByCollisionKey() }{ { name: "user drive", - driveID: suite.its.userDriveID, - rootFolderID: suite.its.userDriveRootFolderID, + driveID: suite.its.user.driveID, + rootFolderID: suite.its.user.driveRootFolderID, }, { name: "site drive", - driveID: suite.its.siteDriveID, - rootFolderID: suite.its.siteDriveRootFolderID, + driveID: suite.its.site.driveID, + rootFolderID: suite.its.site.driveRootFolderID, }, } for _, test := range table { @@ -75,7 +75,7 @@ func (suite *DrivePagerIntgSuite) TestDrives_GetItemsInContainerByCollisionKey() t, ims, "need at least one item to compare in user %s drive %s folder %s", - suite.its.userID, test.driveID, test.rootFolderID) + suite.its.user.id, test.driveID, test.rootFolderID) results, err := suite.its.ac. Drives(). @@ -113,13 +113,13 @@ func (suite *DrivePagerIntgSuite) TestDrives_GetItemIDsInContainer() { }{ { name: "user drive", - driveID: suite.its.userDriveID, - rootFolderID: suite.its.userDriveRootFolderID, + driveID: suite.its.user.driveID, + rootFolderID: suite.its.user.driveRootFolderID, }, { name: "site drive", - driveID: suite.its.siteDriveID, - rootFolderID: suite.its.siteDriveRootFolderID, + driveID: suite.its.site.driveID, + rootFolderID: suite.its.site.driveRootFolderID, }, } for _, test := range table { @@ -149,7 +149,7 @@ func (suite *DrivePagerIntgSuite) TestDrives_GetItemIDsInContainer() { t, igv, "need at least one item to compare in user %s drive %s folder %s", - suite.its.userID, test.driveID, test.rootFolderID) + suite.its.user.id, test.driveID, test.rootFolderID) for _, itm := range igv { expect[ptr.Val(itm.GetId())] = api.DriveItemIDType{ diff --git a/src/pkg/services/m365/api/drive_test.go b/src/pkg/services/m365/api/drive_test.go index 82a889452..28173c27a 100644 --- a/src/pkg/services/m365/api/drive_test.go +++ b/src/pkg/services/m365/api/drive_test.go @@ -76,8 +76,8 @@ func (suite *DriveAPIIntgSuite) TestDrives_PostItemInContainer() { // generate a parent for the test data parent, err := acd.PostItemInContainer( ctx, - suite.its.userDriveID, - suite.its.userDriveRootFolderID, + suite.its.user.driveID, + suite.its.user.driveRootFolderID, newItem(rc.Location, true), control.Replace) require.NoError(t, err, clues.ToCore(err)) @@ -86,7 +86,7 @@ func (suite *DriveAPIIntgSuite) TestDrives_PostItemInContainer() { folder := newItem("collision", true) origFolder, err := acd.PostItemInContainer( ctx, - suite.its.userDriveID, + suite.its.user.driveID, ptr.Val(parent.GetId()), folder, control.Copy) @@ -96,7 +96,7 @@ func (suite *DriveAPIIntgSuite) TestDrives_PostItemInContainer() { file := newItem("collision.txt", false) origFile, err := acd.PostItemInContainer( ctx, - suite.its.userDriveID, + suite.its.user.driveID, ptr.Val(parent.GetId()), file, control.Copy) @@ -211,7 +211,7 @@ func (suite *DriveAPIIntgSuite) TestDrives_PostItemInContainer() { t := suite.T() i, err := acd.PostItemInContainer( ctx, - suite.its.userDriveID, + suite.its.user.driveID, ptr.Val(parent.GetId()), test.postItem, test.onCollision) @@ -239,8 +239,8 @@ func (suite *DriveAPIIntgSuite) TestDrives_PostItemInContainer_replaceFolderRegr // generate a folder for the test data folder, err := acd.PostItemInContainer( ctx, - suite.its.userDriveID, - suite.its.userDriveRootFolderID, + suite.its.user.driveID, + suite.its.user.driveRootFolderID, newItem(rc.Location, true), // skip instead of replace here to get // an ErrItemAlreadyExistsConflict, just in case. @@ -252,7 +252,7 @@ func (suite *DriveAPIIntgSuite) TestDrives_PostItemInContainer_replaceFolderRegr file := newItem(fmt.Sprintf("collision_%d.txt", i), false) f, err := acd.PostItemInContainer( ctx, - suite.its.userDriveID, + suite.its.user.driveID, ptr.Val(folder.GetId()), file, control.Copy) @@ -263,7 +263,7 @@ func (suite *DriveAPIIntgSuite) TestDrives_PostItemInContainer_replaceFolderRegr resultFolder, err := acd.PostItemInContainer( ctx, - suite.its.userDriveID, + suite.its.user.driveID, ptr.Val(folder.GetParentReference().GetId()), newItem(rc.Location, true), control.Replace) @@ -274,7 +274,7 @@ func (suite *DriveAPIIntgSuite) TestDrives_PostItemInContainer_replaceFolderRegr resultFileColl, err := acd.Stable. Client(). Drives(). - ByDriveId(suite.its.userDriveID). + ByDriveId(suite.its.user.driveID). Items(). ByDriveItemId(ptr.Val(resultFolder.GetId())). Children(). diff --git a/src/pkg/services/m365/api/events_pager_test.go b/src/pkg/services/m365/api/events_pager_test.go index 04ba45da9..610b449af 100644 --- a/src/pkg/services/m365/api/events_pager_test.go +++ b/src/pkg/services/m365/api/events_pager_test.go @@ -39,13 +39,13 @@ func (suite *EventsPagerIntgSuite) TestEvents_GetItemsInContainerByCollisionKey( ctx, flush := tester.NewContext(t) defer flush() - container, err := ac.GetContainerByID(ctx, suite.its.userID, "calendar") + container, err := ac.GetContainerByID(ctx, suite.its.user.id, "calendar") require.NoError(t, err, clues.ToCore(err)) evts, err := ac.Stable. Client(). Users(). - ByUserId(suite.its.userID). + ByUserId(suite.its.user.id). Calendars(). ByCalendarId(ptr.Val(container.GetId())). Events(). @@ -63,7 +63,7 @@ func (suite *EventsPagerIntgSuite) TestEvents_GetItemsInContainerByCollisionKey( results, err := suite.its.ac. Events(). - GetItemsInContainerByCollisionKey(ctx, suite.its.userID, "calendar") + GetItemsInContainerByCollisionKey(ctx, suite.its.user.id, "calendar") require.NoError(t, err, clues.ToCore(err)) require.Less(t, 0, len(results), "requires at least one result") diff --git a/src/pkg/services/m365/api/events_test.go b/src/pkg/services/m365/api/events_test.go index cf7d9873f..5b5a2d0db 100644 --- a/src/pkg/services/m365/api/events_test.go +++ b/src/pkg/services/m365/api/events_test.go @@ -289,7 +289,7 @@ func (suite *EventsAPIIntgSuite) TestEvents_canFindNonStandardFolder() { ac := suite.its.ac.Events() rc := testdata.DefaultRestoreConfig("api_calendar_discovery") - cal, err := ac.CreateContainer(ctx, suite.its.userID, "", rc.Location) + cal, err := ac.CreateContainer(ctx, suite.its.user.id, "", rc.Location) require.NoError(t, err, clues.ToCore(err)) var ( @@ -306,7 +306,7 @@ func (suite *EventsAPIIntgSuite) TestEvents_canFindNonStandardFolder() { err = ac.EnumerateContainers( ctx, - suite.its.userID, + suite.its.user.id, "Calendar", findContainer, fault.New(true)) @@ -342,7 +342,7 @@ func (suite *EventsAPIIntgSuite) TestEvents_GetContainerByName() { _, err := suite.its.ac. Events(). - GetContainerByName(ctx, suite.its.userID, "", test.name) + GetContainerByName(ctx, suite.its.user.id, "", test.name) test.expectErr(t, err, clues.ToCore(err)) }) } diff --git a/src/pkg/services/m365/api/groups_test.go b/src/pkg/services/m365/api/groups_test.go index 6a0434196..c57640070 100644 --- a/src/pkg/services/m365/api/groups_test.go +++ b/src/pkg/services/m365/api/groups_test.go @@ -112,7 +112,7 @@ func (suite *GroupsIntgSuite) TestGetAll() { func (suite *GroupsIntgSuite) TestGroups_GetByID() { var ( - groupID = suite.its.groupID + groupID = suite.its.group.id groupsAPI = suite.its.ac.Groups() ) diff --git a/src/pkg/services/m365/api/helper_test.go b/src/pkg/services/m365/api/helper_test.go index 8e8c760c0..76adb3891 100644 --- a/src/pkg/services/m365/api/helper_test.go +++ b/src/pkg/services/m365/api/helper_test.go @@ -74,16 +74,19 @@ func parseableToMap(t *testing.T, thing serialization.Parsable) map[string]any { // Suite Setup // --------------------------------------------------------------------------- +type ids struct { + id string + driveID string + driveRootFolderID string + testContainerID string +} + type intgTesterSetup struct { - ac api.Client - gockAC api.Client - userID string - userDriveID string - userDriveRootFolderID string - siteID string - siteDriveID string - siteDriveRootFolderID string - groupID string + ac api.Client + gockAC api.Client + user ids + site ids + group ids } func newIntegrationTesterSetup(t *testing.T) intgTesterSetup { @@ -106,42 +109,47 @@ func newIntegrationTesterSetup(t *testing.T) intgTesterSetup { // user drive - its.userID = tconfig.M365UserID(t) + its.user.id = tconfig.M365UserID(t) - userDrive, err := its.ac.Users().GetDefaultDrive(ctx, its.userID) + userDrive, err := its.ac.Users().GetDefaultDrive(ctx, its.user.id) require.NoError(t, err, clues.ToCore(err)) - its.userDriveID = ptr.Val(userDrive.GetId()) + its.user.driveID = ptr.Val(userDrive.GetId()) - userDriveRootFolder, err := its.ac.Drives().GetRootFolder(ctx, its.userDriveID) + userDriveRootFolder, err := its.ac.Drives().GetRootFolder(ctx, its.user.driveID) require.NoError(t, err, clues.ToCore(err)) - its.userDriveRootFolderID = ptr.Val(userDriveRootFolder.GetId()) - - its.siteID = tconfig.M365SiteID(t) + its.user.driveRootFolderID = ptr.Val(userDriveRootFolder.GetId()) // site - siteDrive, err := its.ac.Sites().GetDefaultDrive(ctx, its.siteID) + its.site.id = tconfig.M365SiteID(t) + + siteDrive, err := its.ac.Sites().GetDefaultDrive(ctx, its.site.id) require.NoError(t, err, clues.ToCore(err)) - its.siteDriveID = ptr.Val(siteDrive.GetId()) + its.site.driveID = ptr.Val(siteDrive.GetId()) - siteDriveRootFolder, err := its.ac.Drives().GetRootFolder(ctx, its.siteDriveID) + siteDriveRootFolder, err := its.ac.Drives().GetRootFolder(ctx, its.site.driveID) require.NoError(t, err, clues.ToCore(err)) - its.siteDriveRootFolderID = ptr.Val(siteDriveRootFolder.GetId()) + its.site.driveRootFolderID = ptr.Val(siteDriveRootFolder.GetId()) - // group + // groups/teams // use of the TeamID is intentional here, so that we are assured // the group has full usage of the teams api. - its.groupID = tconfig.M365TeamID(t) + its.group.id = tconfig.M365TeamID(t) - team, err := its.ac.Groups().GetByID(ctx, its.groupID) + channel, err := its.ac.Channels(). + GetChannelByName( + ctx, + its.group.id, + "Test") require.NoError(t, err, clues.ToCore(err)) + require.Equal(t, "Test", ptr.Val(channel.GetDisplayName())) - its.groupID = ptr.Val(team.GetId()) + its.group.testContainerID = ptr.Val(channel.GetId()) return its } diff --git a/src/pkg/services/m365/api/lists_test.go b/src/pkg/services/m365/api/lists_test.go index 5864427f2..7250eef67 100644 --- a/src/pkg/services/m365/api/lists_test.go +++ b/src/pkg/services/m365/api/lists_test.go @@ -41,7 +41,7 @@ func (suite *ListsAPIIntgSuite) TestLists_PostDrive() { var ( acl = suite.its.ac.Lists() driveName = testdata.DefaultRestoreConfig("list_api_post_drive").Location - siteID = suite.its.siteID + siteID = suite.its.site.id ) // first post, should have no errors diff --git a/src/pkg/services/m365/api/mail_pager_test.go b/src/pkg/services/m365/api/mail_pager_test.go index d99c428a2..7f367de1d 100644 --- a/src/pkg/services/m365/api/mail_pager_test.go +++ b/src/pkg/services/m365/api/mail_pager_test.go @@ -40,13 +40,13 @@ func (suite *MailPagerIntgSuite) TestMail_GetItemsInContainerByCollisionKey() { ctx, flush := tester.NewContext(t) defer flush() - container, err := ac.GetContainerByID(ctx, suite.its.userID, api.MailInbox) + container, err := ac.GetContainerByID(ctx, suite.its.user.id, api.MailInbox) require.NoError(t, err, clues.ToCore(err)) msgs, err := ac.Stable. Client(). Users(). - ByUserId(suite.its.userID). + ByUserId(suite.its.user.id). MailFolders(). ByMailFolderId(ptr.Val(container.GetId())). Messages(). @@ -62,7 +62,7 @@ func (suite *MailPagerIntgSuite) TestMail_GetItemsInContainerByCollisionKey() { expect := maps.Keys(expectM) - results, err := suite.its.ac.Mail().GetItemsInContainerByCollisionKey(ctx, suite.its.userID, api.MailInbox) + results, err := suite.its.ac.Mail().GetItemsInContainerByCollisionKey(ctx, suite.its.user.id, api.MailInbox) require.NoError(t, err, clues.ToCore(err)) require.Less(t, 0, len(results), "requires at least one result") @@ -101,7 +101,7 @@ func (suite *MailPagerIntgSuite) TestMail_GetItemsIDsInContainer() { msgs, err := ac.Stable. Client(). Users(). - ByUserId(suite.its.userID). + ByUserId(suite.its.user.id). MailFolders(). ByMailFolderId(api.MailInbox). Messages(). @@ -116,7 +116,7 @@ func (suite *MailPagerIntgSuite) TestMail_GetItemsIDsInContainer() { } results, err := suite.its.ac.Mail(). - GetItemIDsInContainer(ctx, suite.its.userID, api.MailInbox) + GetItemIDsInContainer(ctx, suite.its.user.id, api.MailInbox) require.NoError(t, err, clues.ToCore(err)) require.Less(t, 0, len(results), "requires at least one result") require.Equal(t, len(expect), len(results), "must have same count of items") diff --git a/src/pkg/services/m365/api/mail_test.go b/src/pkg/services/m365/api/mail_test.go index 74a4d57b7..e72d5445a 100644 --- a/src/pkg/services/m365/api/mail_test.go +++ b/src/pkg/services/m365/api/mail_test.go @@ -414,7 +414,7 @@ func (suite *MailAPIIntgSuite) TestMail_GetContainerByName() { ctx, flush := tester.NewContext(t) defer flush() - parent, err := acm.CreateContainer(ctx, suite.its.userID, "msgfolderroot", rc.Location) + parent, err := acm.CreateContainer(ctx, suite.its.user.id, "msgfolderroot", rc.Location) require.NoError(t, err, clues.ToCore(err)) table := []struct { @@ -448,7 +448,7 @@ func (suite *MailAPIIntgSuite) TestMail_GetContainerByName() { ctx, flush := tester.NewContext(t) defer flush() - _, err := acm.GetContainerByName(ctx, suite.its.userID, test.parentContainerID, test.name) + _, err := acm.GetContainerByName(ctx, suite.its.user.id, test.parentContainerID, test.name) test.expectErr(t, err, clues.ToCore(err)) }) } @@ -460,10 +460,10 @@ func (suite *MailAPIIntgSuite) TestMail_GetContainerByName() { ctx, flush := tester.NewContext(t) defer flush() - child, err := acm.CreateContainer(ctx, suite.its.userID, pid, rc.Location) + child, err := acm.CreateContainer(ctx, suite.its.user.id, pid, rc.Location) require.NoError(t, err, clues.ToCore(err)) - result, err := acm.GetContainerByName(ctx, suite.its.userID, pid, rc.Location) + result, err := acm.GetContainerByName(ctx, suite.its.user.id, pid, rc.Location) assert.NoError(t, err, clues.ToCore(err)) assert.Equal(t, ptr.Val(child.GetId()), ptr.Val(result.GetId())) }) diff --git a/src/pkg/services/m365/api/users_test.go b/src/pkg/services/m365/api/users_test.go index d7078e497..7ce620ebf 100644 --- a/src/pkg/services/m365/api/users_test.go +++ b/src/pkg/services/m365/api/users_test.go @@ -262,7 +262,7 @@ func (suite *UsersIntgSuite) TestUsers_GetInfo_quotaExceeded() { gock.EnableNetworking() gock.New(graphAPIHostURL). // Wildcard match on the inbox folder ID. - Get(v1APIURLPath("users", suite.its.userID, "mailFolders", "(.*)", "messages", "delta")). + Get(v1APIURLPath("users", suite.its.user.id, "mailFolders", "(.*)", "messages", "delta")). Reply(403). SetHeaders( map[string]string{ @@ -272,7 +272,7 @@ func (suite *UsersIntgSuite) TestUsers_GetInfo_quotaExceeded() { ). BodyString(`{"error":{"code":"ErrorQuotaExceeded","message":"The process failed to get the correct properties."}}`) - output, err := suite.its.gockAC.Users().GetInfo(ctx, suite.its.userID) + output, err := suite.its.gockAC.Users().GetInfo(ctx, suite.its.user.id) require.NoError(t, err, clues.ToCore(err)) assert.True(t, output.Mailbox.QuotaExceeded)