diff --git a/src/internal/m365/collection/drive/collections_test.go b/src/internal/m365/collection/drive/collections_test.go index 6dddb4d81..e716c12ba 100644 --- a/src/internal/m365/collection/drive/collections_test.go +++ b/src/internal/m365/collection/drive/collections_test.go @@ -1179,63 +1179,6 @@ func (suite *OneDriveCollectionsUnitSuite) TestDeserializeMetadata_ReadFailure() require.False(t, canUsePreviousBackup) } -type mockDeltaPageLinker struct { - link *string - delta *string -} - -func (pl *mockDeltaPageLinker) GetOdataNextLink() *string { - return pl.link -} - -func (pl *mockDeltaPageLinker) GetOdataDeltaLink() *string { - return pl.delta -} - -type deltaPagerResult struct { - items []models.DriveItemable - nextLink *string - deltaLink *string - err error -} - -type mockItemPager struct { - // DriveID -> set of return values for queries for that drive. - toReturn []deltaPagerResult - getIdx int -} - -func (p *mockItemPager) GetPage(context.Context) (api.DeltaPageLinker, error) { - if len(p.toReturn) <= p.getIdx { - return nil, assert.AnError - } - - idx := p.getIdx - p.getIdx++ - - return &mockDeltaPageLinker{ - p.toReturn[idx].nextLink, - p.toReturn[idx].deltaLink, - }, p.toReturn[idx].err -} - -func (p *mockItemPager) SetNext(string) {} -func (p *mockItemPager) Reset() {} - -func (p *mockItemPager) ValuesIn(api.DeltaPageLinker) ([]models.DriveItemable, error) { - idx := p.getIdx - if idx > 0 { - // Return values lag by one since we increment in GetPage(). - idx-- - } - - if len(p.toReturn) <= idx { - return nil, assert.AnError - } - - return p.toReturn[idx].items, nil -} - func (suite *OneDriveCollectionsUnitSuite) TestGet() { var ( tenant = "a-tenant" @@ -1283,7 +1226,7 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { table := []struct { name string drives []models.Driveable - items map[string][]deltaPagerResult + items map[string][]apiMock.PagerResult[models.DriveItemable] canUsePreviousBackup bool errCheck assert.ErrorAssertionFunc prevFolderPaths map[string]map[string]string @@ -1302,14 +1245,14 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_DelFileOnly_NoFolders_NoErrors", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), // will be present, not needed delItem("file", driveBasePath1, "root", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1334,14 +1277,14 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_NoFolderDeltas_NoErrors", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("file", "file", driveBasePath1, "root", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1366,15 +1309,15 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_NoErrors", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1403,16 +1346,16 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_NoErrors_FileRenamedMultiple", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), driveItem("file", "file2", driveBasePath1+"/folder", "folder", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1441,16 +1384,16 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_NoErrors_FileMovedMultiple", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), driveItem("file", "file2", driveBasePath1, "root", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1481,15 +1424,15 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_EmptyDelta_NoErrors", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), }, - deltaLink: &empty, // probably will never happen with graph + DeltaLink: &empty, // probably will never happen with graph }, }, }, @@ -1518,23 +1461,23 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_TwoItemPages_NoErrors", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), }, - nextLink: &next, + NextLink: &next, }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file2", "file2", driveBasePath1+"/folder", "folder", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1568,25 +1511,25 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { drive1, drive2, }, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, driveID2: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root2"), driveItem("folder2", "folder", driveBasePath2, "root2", false, true, false), driveItem("file2", "file", driveBasePath2+"/folder", "folder2", true, false, false), }, - deltaLink: &delta2, + DeltaLink: &delta2, }, }, }, @@ -1630,25 +1573,25 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { drive1, drive2, }, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, driveID2: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath2, "root", false, true, false), driveItem("file2", "file", driveBasePath2+"/folder", "folder", true, false, false), }, - deltaLink: &delta2, + DeltaLink: &delta2, }, }, }, @@ -1689,10 +1632,10 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_Errors", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - err: assert.AnError, + Err: assert.AnError, }, }, }, @@ -1709,17 +1652,17 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_DeltaError", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - err: getDeltaError(), + Err: getDeltaError(), }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("file", "file", driveBasePath1, "root", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1744,25 +1687,25 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_TwoItemPage_DeltaError", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - err: getDeltaError(), + Err: getDeltaError(), }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("file", "file", driveBasePath1, "root", true, false, false), }, - nextLink: &next, + NextLink: &next, }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file2", "file", driveBasePath1+"/folder", "folder", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1790,22 +1733,22 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_TwoItemPage_NoDeltaError", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("file", "file", driveBasePath1, "root", true, false, false), }, - nextLink: &next, + NextLink: &next, }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file2", "file", driveBasePath1+"/folder", "folder", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1837,18 +1780,18 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_InvalidPrevDelta_DeleteNonExistentFolder", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - err: getDeltaError(), + Err: getDeltaError(), }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder2", "folder2", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder2", "folder2", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1884,18 +1827,18 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive_OneItemPage_InvalidPrevDelta_AnotherFolderAtDeletedLocation", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - err: getDeltaError(), + Err: getDeltaError(), }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder2", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder2", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1934,25 +1877,25 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "OneDrive Two Item Pages with Malware", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), malwareItem("malware", "malware", driveBasePath1+"/folder", "folder", true, false, false), }, - nextLink: &next, + NextLink: &next, }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file2", "file2", driveBasePath1+"/folder", "folder", true, false, false), malwareItem("malware2", "malware2", driveBasePath1+"/folder", "folder", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -1984,28 +1927,28 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "One Drive Delta Error Deleted Folder In New Results", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - err: getDeltaError(), + Err: getDeltaError(), }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), driveItem("folder2", "folder2", driveBasePath1, "root", false, true, false), driveItem("file2", "file2", driveBasePath1+"/folder2", "folder2", true, false, false), }, - nextLink: &next, + NextLink: &next, }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), delItem("folder2", driveBasePath1, "root", false, true, false), delItem("file2", driveBasePath1, "root", true, false, false), }, - deltaLink: &delta2, + DeltaLink: &delta2, }, }, }, @@ -2042,17 +1985,17 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "One Drive Delta Error Random Folder Delete", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - err: getDeltaError(), + Err: getDeltaError(), }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), delItem("folder", driveBasePath1, "root", false, true, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -2085,17 +2028,17 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "One Drive Delta Error Random Item Delete", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - err: getDeltaError(), + Err: getDeltaError(), }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), delItem("file", driveBasePath1, "root", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -2125,23 +2068,23 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "One Drive Folder Made And Deleted", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), }, - nextLink: &next, + NextLink: &next, }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), delItem("folder", driveBasePath1, "root", false, true, false), delItem("file", driveBasePath1, "root", true, false, false), }, - deltaLink: &delta2, + DeltaLink: &delta2, }, }, }, @@ -2169,22 +2112,22 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "One Drive Item Made And Deleted", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), driveItem("folder", "folder", driveBasePath1, "root", false, true, false), driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false), }, - nextLink: &next, + NextLink: &next, }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), delItem("file", driveBasePath1, "root", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -2215,14 +2158,14 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "One Drive Random Folder Delete", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), delItem("folder", driveBasePath1, "root", false, true, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -2250,14 +2193,14 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "One Drive Random Item Delete", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), delItem("file", driveBasePath1, "root", true, false, false), }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -2285,13 +2228,13 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { { name: "TwoPriorDrives_OneTombstoned", drives: []models.Driveable{drive1}, - items: map[string][]deltaPagerResult{ + items: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID1: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ driveRootItem("root"), // will be present }, - deltaLink: &delta, + DeltaLink: &delta, }, }, }, @@ -2322,17 +2265,17 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { ctx, flush := tester.NewContext(t) defer flush() - mockDrivePager := &apiMock.DrivePager{ - ToReturn: []apiMock.PagerResult{ - {Drives: test.drives}, + mockDrivePager := &apiMock.Pager[models.Driveable]{ + ToReturn: []apiMock.PagerResult[models.Driveable]{ + {Values: test.drives}, }, } - itemPagers := map[string]api.DriveItemDeltaEnumerator{} + itemPagers := map[string]api.DeltaPager[models.DriveItemable]{} for driveID := range test.items { - itemPagers[driveID] = &mockItemPager{ - toReturn: test.items[driveID], + itemPagers[driveID] = &apiMock.DeltaPager[models.DriveItemable]{ + ToReturn: test.items[driveID], } } @@ -2583,7 +2526,7 @@ func (suite *OneDriveCollectionsUnitSuite) TestCollectItems() { table := []struct { name string - items []deltaPagerResult + items []apiMock.PagerResult[models.DriveItemable] deltaURL string prevDeltaSuccess bool prevDelta string @@ -2592,8 +2535,8 @@ func (suite *OneDriveCollectionsUnitSuite) TestCollectItems() { { name: "delta on first run", deltaURL: delta, - items: []deltaPagerResult{ - {deltaLink: &delta}, + items: []apiMock.PagerResult[models.DriveItemable]{ + {DeltaLink: &delta}, }, prevDeltaSuccess: true, prevDelta: prevDelta, @@ -2601,8 +2544,8 @@ func (suite *OneDriveCollectionsUnitSuite) TestCollectItems() { { name: "empty prev delta", deltaURL: delta, - items: []deltaPagerResult{ - {deltaLink: &delta}, + items: []apiMock.PagerResult[models.DriveItemable]{ + {DeltaLink: &delta}, }, prevDeltaSuccess: false, prevDelta: "", @@ -2610,9 +2553,9 @@ func (suite *OneDriveCollectionsUnitSuite) TestCollectItems() { { name: "next then delta", deltaURL: delta, - items: []deltaPagerResult{ - {nextLink: &next}, - {deltaLink: &delta}, + items: []apiMock.PagerResult[models.DriveItemable]{ + {NextLink: &next}, + {DeltaLink: &delta}, }, prevDeltaSuccess: true, prevDelta: prevDelta, @@ -2620,18 +2563,18 @@ func (suite *OneDriveCollectionsUnitSuite) TestCollectItems() { { name: "invalid prev delta", deltaURL: delta, - items: []deltaPagerResult{ - {err: getDeltaError()}, - {deltaLink: &delta}, // works on retry + items: []apiMock.PagerResult[models.DriveItemable]{ + {Err: getDeltaError()}, + {DeltaLink: &delta}, // works on retry }, prevDelta: prevDelta, prevDeltaSuccess: false, }, { name: "fail a normal delta query", - items: []deltaPagerResult{ - {nextLink: &next}, - {err: assert.AnError}, + items: []apiMock.PagerResult[models.DriveItemable]{ + {NextLink: &next}, + {Err: assert.AnError}, }, prevDelta: prevDelta, prevDeltaSuccess: true, @@ -2645,8 +2588,8 @@ func (suite *OneDriveCollectionsUnitSuite) TestCollectItems() { ctx, flush := tester.NewContext(t) defer flush() - itemPager := &mockItemPager{ - toReturn: test.items, + itemPager := &apiMock.DeltaPager[models.DriveItemable]{ + ToReturn: test.items, } collectorFunc := func( @@ -2687,7 +2630,7 @@ func (suite *OneDriveCollectionsUnitSuite) TestAddURLCacheToDriveCollections() { table := []struct { name string - items []deltaPagerResult + items []apiMock.PagerResult[any] deltaURL string prevDeltaSuccess bool prevDelta string @@ -2704,8 +2647,8 @@ func (suite *OneDriveCollectionsUnitSuite) TestAddURLCacheToDriveCollections() { ctx, flush := tester.NewContext(t) defer flush() - itemPagers := map[string]api.DriveItemDeltaEnumerator{} - itemPagers[driveID] = &mockItemPager{} + itemPagers := map[string]api.DeltaPager[models.DriveItemable]{} + itemPagers[driveID] = &apiMock.DeltaPager[models.DriveItemable]{} mbh := mock.DefaultOneDriveBH() mbh.ItemPagerV = itemPagers diff --git a/src/internal/m365/collection/drive/handlers.go b/src/internal/m365/collection/drive/handlers.go index 239bcbef5..11860b802 100644 --- a/src/internal/m365/collection/drive/handlers.go +++ b/src/internal/m365/collection/drive/handlers.go @@ -50,7 +50,7 @@ type BackupHandler interface { // ServiceCat returns the service and category used by this implementation. ServiceCat() (path.ServiceType, path.CategoryType) - NewItemPager(driveID, link string, fields []string) api.DriveItemDeltaEnumerator + NewItemPager(driveID, link string, fields []string) api.DeltaPager[models.DriveItemable] // FormatDisplayPath creates a human-readable string to represent the // provided path. FormatDisplayPath(driveName string, parentPath *path.Builder) string @@ -62,7 +62,7 @@ type BackupHandler interface { } type NewDrivePagerer interface { - NewDrivePager(resourceOwner string, fields []string) api.DrivePager + NewDrivePager(resourceOwner string, fields []string) api.Pager[models.Driveable] } type GetItemPermissioner interface { diff --git a/src/internal/m365/collection/drive/item_collector.go b/src/internal/m365/collection/drive/item_collector.go index d737c4abd..a0099a584 100644 --- a/src/internal/m365/collection/drive/item_collector.go +++ b/src/internal/m365/collection/drive/item_collector.go @@ -42,7 +42,7 @@ type itemCollector func( // provided `collector` method func collectItems( ctx context.Context, - pager api.DriveItemDeltaEnumerator, + pager api.DeltaPager[models.DriveItemable], driveID, driveName string, collector itemCollector, oldPaths map[string]string, @@ -85,7 +85,7 @@ func collectItems( invalidPrevDelta = true newPaths = map[string]string{} - pager.Reset() + pager.Reset(ctx) continue } diff --git a/src/internal/m365/collection/drive/item_collector_test.go b/src/internal/m365/collection/drive/item_collector_test.go index f8aca7eb6..d57ca23f6 100644 --- a/src/internal/m365/collection/drive/item_collector_test.go +++ b/src/internal/m365/collection/drive/item_collector_test.go @@ -72,26 +72,26 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { resultDrives = append(resultDrives, d) } - tooManyRetries := make([]mock.PagerResult, 0, maxDrivesRetries+1) + tooManyRetries := make([]mock.PagerResult[models.Driveable], 0, maxDrivesRetries+1) for i := 0; i < maxDrivesRetries+1; i++ { - tooManyRetries = append(tooManyRetries, mock.PagerResult{ + tooManyRetries = append(tooManyRetries, mock.PagerResult[models.Driveable]{ Err: context.DeadlineExceeded, }) } table := []struct { name string - pagerResults []mock.PagerResult + pagerResults []mock.PagerResult[models.Driveable] retry bool expectedErr assert.ErrorAssertionFunc expectedResults []models.Driveable }{ { name: "AllOneResultNilNextLink", - pagerResults: []mock.PagerResult{ + pagerResults: []mock.PagerResult[models.Driveable]{ { - Drives: resultDrives, + Values: resultDrives, NextLink: nil, Err: nil, }, @@ -102,9 +102,9 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { }, { name: "AllOneResultEmptyNextLink", - pagerResults: []mock.PagerResult{ + pagerResults: []mock.PagerResult[models.Driveable]{ { - Drives: resultDrives, + Values: resultDrives, NextLink: &emptyLink, Err: nil, }, @@ -115,14 +115,14 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { }, { name: "SplitResultsNilNextLink", - pagerResults: []mock.PagerResult{ + pagerResults: []mock.PagerResult[models.Driveable]{ { - Drives: resultDrives[:numDriveResults/2], + Values: resultDrives[:numDriveResults/2], NextLink: &link, Err: nil, }, { - Drives: resultDrives[numDriveResults/2:], + Values: resultDrives[numDriveResults/2:], NextLink: nil, Err: nil, }, @@ -133,14 +133,14 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { }, { name: "SplitResultsEmptyNextLink", - pagerResults: []mock.PagerResult{ + pagerResults: []mock.PagerResult[models.Driveable]{ { - Drives: resultDrives[:numDriveResults/2], + Values: resultDrives[:numDriveResults/2], NextLink: &link, Err: nil, }, { - Drives: resultDrives[numDriveResults/2:], + Values: resultDrives[numDriveResults/2:], NextLink: &emptyLink, Err: nil, }, @@ -151,14 +151,14 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { }, { name: "NonRetryableError", - pagerResults: []mock.PagerResult{ + pagerResults: []mock.PagerResult[models.Driveable]{ { - Drives: resultDrives, + Values: resultDrives, NextLink: &link, Err: nil, }, { - Drives: nil, + Values: nil, NextLink: nil, Err: assert.AnError, }, @@ -169,9 +169,9 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { }, { name: "MySiteURLNotFound", - pagerResults: []mock.PagerResult{ + pagerResults: []mock.PagerResult[models.Driveable]{ { - Drives: nil, + Values: nil, NextLink: nil, Err: graph.Stack(ctx, mySiteURLNotFound), }, @@ -182,9 +182,9 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { }, { name: "MySiteNotFound", - pagerResults: []mock.PagerResult{ + pagerResults: []mock.PagerResult[models.Driveable]{ { - Drives: nil, + Values: nil, NextLink: nil, Err: graph.Stack(ctx, mySiteNotFound), }, @@ -195,19 +195,19 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { }, { name: "SplitResultsContextTimeoutWithRetries", - pagerResults: []mock.PagerResult{ + pagerResults: []mock.PagerResult[models.Driveable]{ { - Drives: resultDrives[:numDriveResults/2], + Values: resultDrives[:numDriveResults/2], NextLink: &link, Err: nil, }, { - Drives: nil, + Values: nil, NextLink: nil, Err: context.DeadlineExceeded, }, { - Drives: resultDrives[numDriveResults/2:], + Values: resultDrives[numDriveResults/2:], NextLink: &emptyLink, Err: nil, }, @@ -218,19 +218,19 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { }, { name: "SplitResultsContextTimeoutNoRetries", - pagerResults: []mock.PagerResult{ + pagerResults: []mock.PagerResult[models.Driveable]{ { - Drives: resultDrives[:numDriveResults/2], + Values: resultDrives[:numDriveResults/2], NextLink: &link, Err: nil, }, { - Drives: nil, + Values: nil, NextLink: nil, Err: context.DeadlineExceeded, }, { - Drives: resultDrives[numDriveResults/2:], + Values: resultDrives[numDriveResults/2:], NextLink: &emptyLink, Err: nil, }, @@ -242,9 +242,9 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { { name: "TooManyRetries", pagerResults: append( - []mock.PagerResult{ + []mock.PagerResult[models.Driveable]{ { - Drives: resultDrives[:numDriveResults/2], + Values: resultDrives[:numDriveResults/2], NextLink: &link, Err: nil, }, @@ -263,7 +263,7 @@ func (suite *ItemCollectorUnitSuite) TestDrives() { ctx, flush := tester.NewContext(t) defer flush() - pager := &mock.DrivePager{ + pager := &mock.Pager[models.Driveable]{ ToReturn: test.pagerResults, } diff --git a/src/internal/m365/collection/drive/item_handler.go b/src/internal/m365/collection/drive/item_handler.go index 58fccd7a8..80eea5b06 100644 --- a/src/internal/m365/collection/drive/item_handler.go +++ b/src/internal/m365/collection/drive/item_handler.go @@ -66,14 +66,14 @@ func (h itemBackupHandler) ServiceCat() (path.ServiceType, path.CategoryType) { func (h itemBackupHandler) NewDrivePager( resourceOwner string, fields []string, -) api.DrivePager { +) api.Pager[models.Driveable] { return h.ac.NewUserDrivePager(resourceOwner, fields) } func (h itemBackupHandler) NewItemPager( driveID, link string, fields []string, -) api.DriveItemDeltaEnumerator { +) api.DeltaPager[models.DriveItemable] { return h.ac.NewDriveItemDeltaPager(driveID, link, fields) } @@ -145,7 +145,7 @@ func (h itemRestoreHandler) PostDrive( func (h itemRestoreHandler) NewDrivePager( resourceOwner string, fields []string, -) api.DrivePager { +) api.Pager[models.Driveable] { return h.ac.NewUserDrivePager(resourceOwner, fields) } diff --git a/src/internal/m365/collection/drive/library_handler.go b/src/internal/m365/collection/drive/library_handler.go index e06a279db..a27033424 100644 --- a/src/internal/m365/collection/drive/library_handler.go +++ b/src/internal/m365/collection/drive/library_handler.go @@ -69,14 +69,14 @@ func (h libraryBackupHandler) ServiceCat() (path.ServiceType, path.CategoryType) func (h libraryBackupHandler) NewDrivePager( resourceOwner string, fields []string, -) api.DrivePager { +) api.Pager[models.Driveable] { return h.ac.NewSiteDrivePager(resourceOwner, fields) } func (h libraryBackupHandler) NewItemPager( driveID, link string, fields []string, -) api.DriveItemDeltaEnumerator { +) api.DeltaPager[models.DriveItemable] { return h.ac.NewDriveItemDeltaPager(driveID, link, fields) } @@ -184,7 +184,7 @@ func (h libraryRestoreHandler) PostDrive( func (h libraryRestoreHandler) NewDrivePager( resourceOwner string, fields []string, -) api.DrivePager { +) api.Pager[models.Driveable] { return h.ac.Drives().NewSiteDrivePager(resourceOwner, fields) } diff --git a/src/internal/m365/collection/drive/restore_test.go b/src/internal/m365/collection/drive/restore_test.go index f82630433..731ccef77 100644 --- a/src/internal/m365/collection/drive/restore_test.go +++ b/src/internal/m365/collection/drive/restore_test.go @@ -408,7 +408,7 @@ func (suite *RestoreUnitSuite) TestRestoreCaches_AddDrive() { type mockGDPARF struct { err error rootFolder models.DriveItemable - pager *apiMock.DrivePager + pager *apiMock.Pager[models.Driveable] } func (m *mockGDPARF) GetRootFolder( @@ -421,7 +421,7 @@ func (m *mockGDPARF) GetRootFolder( func (m *mockGDPARF) NewDrivePager( string, []string, -) api.DrivePager { +) api.Pager[models.Driveable] { return m.pager } @@ -439,16 +439,16 @@ func (suite *RestoreUnitSuite) TestRestoreCaches_Populate() { table := []struct { name string - mock *apiMock.DrivePager + mock *apiMock.Pager[models.Driveable] expectErr require.ErrorAssertionFunc expectLen int checkValues bool }{ { name: "no results", - mock: &apiMock.DrivePager{ - ToReturn: []apiMock.PagerResult{ - {Drives: []models.Driveable{}}, + mock: &apiMock.Pager[models.Driveable]{ + ToReturn: []apiMock.PagerResult[models.Driveable]{ + {Values: []models.Driveable{}}, }, }, expectErr: require.NoError, @@ -456,9 +456,9 @@ func (suite *RestoreUnitSuite) TestRestoreCaches_Populate() { }, { name: "one result", - mock: &apiMock.DrivePager{ - ToReturn: []apiMock.PagerResult{ - {Drives: []models.Driveable{md}}, + mock: &apiMock.Pager[models.Driveable]{ + ToReturn: []apiMock.PagerResult[models.Driveable]{ + {Values: []models.Driveable{md}}, }, }, expectErr: require.NoError, @@ -467,8 +467,8 @@ func (suite *RestoreUnitSuite) TestRestoreCaches_Populate() { }, { name: "error", - mock: &apiMock.DrivePager{ - ToReturn: []apiMock.PagerResult{ + mock: &apiMock.Pager[models.Driveable]{ + ToReturn: []apiMock.PagerResult[models.Driveable]{ {Err: assert.AnError}, }, }, diff --git a/src/internal/m365/collection/drive/url_cache.go b/src/internal/m365/collection/drive/url_cache.go index 6c06866c6..1a8cc7899 100644 --- a/src/internal/m365/collection/drive/url_cache.go +++ b/src/internal/m365/collection/drive/url_cache.go @@ -47,7 +47,7 @@ type urlCache struct { refreshMu sync.Mutex deltaQueryCount int - itemPager api.DriveItemDeltaEnumerator + itemPager api.DeltaPager[models.DriveItemable] errs *fault.Bus } @@ -56,7 +56,7 @@ type urlCache struct { func newURLCache( driveID, prevDelta string, refreshInterval time.Duration, - itemPager api.DriveItemDeltaEnumerator, + itemPager api.DeltaPager[models.DriveItemable], errs *fault.Bus, ) (*urlCache, error) { err := validateCacheParams( @@ -83,7 +83,7 @@ func newURLCache( func validateCacheParams( driveID string, refreshInterval time.Duration, - itemPager api.DriveItemDeltaEnumerator, + itemPager api.DeltaPager[models.DriveItemable], ) error { if len(driveID) == 0 { return clues.New("drive id is empty") @@ -182,7 +182,7 @@ func (uc *urlCache) deltaQuery( ) error { logger.Ctx(ctx).Debug("starting delta query") // Reset item pager to remove any previous state - uc.itemPager.Reset() + uc.itemPager.Reset(ctx) _, _, _, err := collectItems( ctx, diff --git a/src/internal/m365/collection/drive/url_cache_test.go b/src/internal/m365/collection/drive/url_cache_test.go index 68b5b8a8b..5b35ddff2 100644 --- a/src/internal/m365/collection/drive/url_cache_test.go +++ b/src/internal/m365/collection/drive/url_cache_test.go @@ -24,6 +24,7 @@ import ( "github.com/alcionai/corso/src/pkg/control/testdata" "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/services/m365/api" + apiMock "github.com/alcionai/corso/src/pkg/services/m365/api/mock" ) type URLCacheIntegrationSuite struct { @@ -209,20 +210,20 @@ func (suite *URLCacheUnitSuite) TestGetItemProperties() { table := []struct { name string - pagerResult map[string][]deltaPagerResult + pagerResult map[string][]apiMock.PagerResult[models.DriveItemable] expectedItemProps map[string]itemProps expectedErr require.ErrorAssertionFunc cacheAssert func(*urlCache, time.Time) }{ { name: "single item in cache", - pagerResult: map[string][]deltaPagerResult{ + pagerResult: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ fileItem("1", "file1", "root", "root", "https://dummy1.com", false), }, - deltaLink: &deltaString, + DeltaLink: &deltaString, }, }, }, @@ -241,17 +242,17 @@ func (suite *URLCacheUnitSuite) TestGetItemProperties() { }, { name: "multiple items in cache", - pagerResult: map[string][]deltaPagerResult{ + pagerResult: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ fileItem("1", "file1", "root", "root", "https://dummy1.com", false), fileItem("2", "file2", "root", "root", "https://dummy2.com", false), fileItem("3", "file3", "root", "root", "https://dummy3.com", false), fileItem("4", "file4", "root", "root", "https://dummy4.com", false), fileItem("5", "file5", "root", "root", "https://dummy5.com", false), }, - deltaLink: &deltaString, + DeltaLink: &deltaString, }, }, }, @@ -286,17 +287,17 @@ func (suite *URLCacheUnitSuite) TestGetItemProperties() { }, { name: "duplicate items with potentially new urls", - pagerResult: map[string][]deltaPagerResult{ + pagerResult: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ fileItem("1", "file1", "root", "root", "https://dummy1.com", false), fileItem("2", "file2", "root", "root", "https://dummy2.com", false), fileItem("3", "file3", "root", "root", "https://dummy3.com", false), fileItem("1", "file1", "root", "root", "https://test1.com", false), fileItem("2", "file2", "root", "root", "https://test2.com", false), }, - deltaLink: &deltaString, + DeltaLink: &deltaString, }, }, }, @@ -323,15 +324,15 @@ func (suite *URLCacheUnitSuite) TestGetItemProperties() { }, { name: "deleted items", - pagerResult: map[string][]deltaPagerResult{ + pagerResult: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ fileItem("1", "file1", "root", "root", "https://dummy1.com", false), fileItem("2", "file2", "root", "root", "https://dummy2.com", false), fileItem("1", "file1", "root", "root", "https://dummy1.com", true), }, - deltaLink: &deltaString, + DeltaLink: &deltaString, }, }, }, @@ -354,13 +355,13 @@ func (suite *URLCacheUnitSuite) TestGetItemProperties() { }, { name: "item not found in cache", - pagerResult: map[string][]deltaPagerResult{ + pagerResult: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ fileItem("1", "file1", "root", "root", "https://dummy1.com", false), }, - deltaLink: &deltaString, + DeltaLink: &deltaString, }, }, }, @@ -376,20 +377,20 @@ func (suite *URLCacheUnitSuite) TestGetItemProperties() { }, { name: "multi-page delta query error", - pagerResult: map[string][]deltaPagerResult{ + pagerResult: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ fileItem("1", "file1", "root", "root", "https://dummy1.com", false), }, - nextLink: &next, + NextLink: &next, }, { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ fileItem("2", "file2", "root", "root", "https://dummy2.com", false), }, - deltaLink: &deltaString, - err: errors.New("delta query error"), + DeltaLink: &deltaString, + Err: errors.New("delta query error"), }, }, }, @@ -407,14 +408,14 @@ func (suite *URLCacheUnitSuite) TestGetItemProperties() { { name: "folder item", - pagerResult: map[string][]deltaPagerResult{ + pagerResult: map[string][]apiMock.PagerResult[models.DriveItemable]{ driveID: { { - items: []models.DriveItemable{ + Values: []models.DriveItemable{ fileItem("1", "file1", "root", "root", "https://dummy1.com", false), driveItem("2", "folder2", "root", "root", false, true, false), }, - deltaLink: &deltaString, + DeltaLink: &deltaString, }, }, }, @@ -436,8 +437,8 @@ func (suite *URLCacheUnitSuite) TestGetItemProperties() { ctx, flush := tester.NewContext(t) defer flush() - itemPager := &mockItemPager{ - toReturn: test.pagerResult[driveID], + itemPager := &apiMock.DeltaPager[models.DriveItemable]{ + ToReturn: test.pagerResult[driveID], } cache, err := newURLCache( @@ -487,7 +488,7 @@ func (suite *URLCacheUnitSuite) TestNeedsRefresh() { driveID, "", refreshInterval, - &mockItemPager{}, + &apiMock.DeltaPager[models.DriveItemable]{}, fault.New(true)) require.NoError(t, err, clues.ToCore(err)) @@ -516,7 +517,7 @@ func (suite *URLCacheUnitSuite) TestNewURLCache() { name string driveID string refreshInt time.Duration - itemPager api.DriveItemDeltaEnumerator + itemPager api.DeltaPager[models.DriveItemable] errors *fault.Bus expectedErr require.ErrorAssertionFunc }{ @@ -524,7 +525,7 @@ func (suite *URLCacheUnitSuite) TestNewURLCache() { name: "invalid driveID", driveID: "", refreshInt: 1 * time.Hour, - itemPager: &mockItemPager{}, + itemPager: &apiMock.DeltaPager[models.DriveItemable]{}, errors: fault.New(true), expectedErr: require.Error, }, @@ -532,7 +533,7 @@ func (suite *URLCacheUnitSuite) TestNewURLCache() { name: "invalid refresh interval", driveID: "drive1", refreshInt: 100 * time.Millisecond, - itemPager: &mockItemPager{}, + itemPager: &apiMock.DeltaPager[models.DriveItemable]{}, errors: fault.New(true), expectedErr: require.Error, }, @@ -548,7 +549,7 @@ func (suite *URLCacheUnitSuite) TestNewURLCache() { name: "valid", driveID: "drive1", refreshInt: 1 * time.Hour, - itemPager: &mockItemPager{}, + itemPager: &apiMock.DeltaPager[models.DriveItemable]{}, errors: fault.New(true), expectedErr: require.NoError, }, diff --git a/src/internal/m365/service/onedrive/mock/handlers.go b/src/internal/m365/service/onedrive/mock/handlers.go index 20beb6bca..d8b12b3bb 100644 --- a/src/internal/m365/service/onedrive/mock/handlers.go +++ b/src/internal/m365/service/onedrive/mock/handlers.go @@ -34,9 +34,9 @@ type BackupHandler struct { Service path.ServiceType Category path.CategoryType - DrivePagerV api.DrivePager + DrivePagerV api.Pager[models.Driveable] // driveID -> itemPager - ItemPagerV map[string]api.DriveItemDeltaEnumerator + ItemPagerV map[string]api.DeltaPager[models.DriveItemable] LocationIDFn locationIDer @@ -103,11 +103,11 @@ func (h BackupHandler) ServiceCat() (path.ServiceType, path.CategoryType) { return h.Service, h.Category } -func (h BackupHandler) NewDrivePager(string, []string) api.DrivePager { +func (h BackupHandler) NewDrivePager(string, []string) api.Pager[models.Driveable] { return h.DrivePagerV } -func (h BackupHandler) NewItemPager(driveID string, _ string, _ []string) api.DriveItemDeltaEnumerator { +func (h BackupHandler) NewItemPager(driveID string, _ string, _ []string) api.DeltaPager[models.DriveItemable] { return h.ItemPagerV[driveID] } @@ -249,7 +249,7 @@ type RestoreHandler struct { PostItemResp models.DriveItemable PostItemErr error - DrivePagerV api.DrivePager + DrivePagerV api.Pager[models.Driveable] PostDriveResp models.Driveable PostDriveErr error @@ -264,7 +264,7 @@ func (h RestoreHandler) PostDrive( return h.PostDriveResp, h.PostDriveErr } -func (h RestoreHandler) NewDrivePager(string, []string) api.DrivePager { +func (h RestoreHandler) NewDrivePager(string, []string) api.Pager[models.Driveable] { return h.DrivePagerV } diff --git a/src/pkg/services/m365/api/contacts.go b/src/pkg/services/m365/api/contacts.go index 9f9288420..e2401c9fd 100644 --- a/src/pkg/services/m365/api/contacts.go +++ b/src/pkg/services/m365/api/contacts.go @@ -82,13 +82,10 @@ func (c Contacts) DeleteContainer( return nil } -// prefer GetContainerByID where possible. -// use this only in cases where the models.ContactFolderable -// is required. -func (c Contacts) GetFolder( +func (c Contacts) GetContainerByID( ctx context.Context, userID, containerID string, -) (models.ContactFolderable, error) { +) (graph.Container, error) { config := &users.ItemContactFoldersContactFolderItemRequestBuilderGetRequestConfiguration{ QueryParameters: &users.ItemContactFoldersContactFolderItemRequestBuilderGetQueryParameters{ Select: idAnd(displayName, parentFolderID), @@ -109,14 +106,6 @@ func (c Contacts) GetFolder( return resp, nil } -// interface-compliant wrapper of GetFolder -func (c Contacts) GetContainerByID( - ctx context.Context, - userID, containerID string, -) (graph.Container, error) { - return c.GetFolder(ctx, userID, containerID) -} - // GetContainerByName fetches a folder by name func (c Contacts) GetContainerByName( ctx context.Context, diff --git a/src/pkg/services/m365/api/contacts_pager.go b/src/pkg/services/m365/api/contacts_pager.go index 9a86f1e00..b253fd35c 100644 --- a/src/pkg/services/m365/api/contacts_pager.go +++ b/src/pkg/services/m365/api/contacts_pager.go @@ -191,7 +191,7 @@ func (c Contacts) GetItemIDsInContainer( // item ID pager // --------------------------------------------------------------------------- -var _ itemIDPager = &contactIDPager{} +var _ DeltaPager[getIDAndAddtler] = &contactIDPager{} type contactIDPager struct { gs graph.Servicer @@ -203,7 +203,7 @@ func (c Contacts) NewContactIDsPager( ctx context.Context, userID, containerID string, immutableIDs bool, -) itemIDPager { +) DeltaPager[getIDAndAddtler] { config := &users.ItemContactFoldersItemContactsRequestBuilderGetRequestConfiguration{ QueryParameters: &users.ItemContactFoldersItemContactsRequestBuilderGetQueryParameters{ Select: idAnd(parentFolderID), @@ -223,7 +223,7 @@ func (c Contacts) NewContactIDsPager( return &contactIDPager{c.Stable, builder, config} } -func (p *contactIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) { +func (p *contactIDPager) GetPage(ctx context.Context) (DeltaPageLinker, error) { resp, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) @@ -232,14 +232,14 @@ func (p *contactIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) { return EmptyDeltaLinker[models.Contactable]{PageLinkValuer: resp}, nil } -func (p *contactIDPager) setNext(nextLink string) { +func (p *contactIDPager) SetNext(nextLink string) { p.builder = users.NewItemContactFoldersItemContactsRequestBuilder(nextLink, p.gs.Adapter()) } // non delta pagers don't need reset -func (p *contactIDPager) reset(context.Context) {} +func (p *contactIDPager) Reset(context.Context) {} -func (p *contactIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) { +func (p *contactIDPager) ValuesIn(pl PageLinker) ([]getIDAndAddtler, error) { return toValues[models.Contactable](pl) } @@ -247,7 +247,7 @@ func (p *contactIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) { // delta item ID pager // --------------------------------------------------------------------------- -var _ itemIDPager = &contactDeltaIDPager{} +var _ DeltaPager[getIDAndAddtler] = &contactDeltaIDPager{} type contactDeltaIDPager struct { gs graph.Servicer @@ -271,7 +271,7 @@ func (c Contacts) NewContactDeltaIDsPager( ctx context.Context, userID, containerID, oldDelta string, immutableIDs bool, -) itemIDPager { +) DeltaPager[getIDAndAddtler] { options := &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration{ QueryParameters: &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetQueryParameters{ Select: idAnd(parentFolderID), @@ -290,7 +290,7 @@ func (c Contacts) NewContactDeltaIDsPager( return &contactDeltaIDPager{c.Stable, userID, containerID, builder, options} } -func (p *contactDeltaIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) { +func (p *contactDeltaIDPager) GetPage(ctx context.Context) (DeltaPageLinker, error) { resp, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) @@ -299,15 +299,15 @@ func (p *contactDeltaIDPager) getPage(ctx context.Context) (DeltaPageLinker, err return resp, nil } -func (p *contactDeltaIDPager) setNext(nextLink string) { +func (p *contactDeltaIDPager) SetNext(nextLink string) { p.builder = users.NewItemContactFoldersItemContactsDeltaRequestBuilder(nextLink, p.gs.Adapter()) } -func (p *contactDeltaIDPager) reset(ctx context.Context) { +func (p *contactDeltaIDPager) Reset(ctx context.Context) { p.builder = getContactDeltaBuilder(ctx, p.gs, p.userID, p.containerID, p.options) } -func (p *contactDeltaIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) { +func (p *contactDeltaIDPager) ValuesIn(pl PageLinker) ([]getIDAndAddtler, error) { return toValues[models.Contactable](pl) } diff --git a/src/pkg/services/m365/api/drive_pager.go b/src/pkg/services/m365/api/drive_pager.go index 7a8c100a3..1aa485200 100644 --- a/src/pkg/services/m365/api/drive_pager.go +++ b/src/pkg/services/m365/api/drive_pager.go @@ -120,20 +120,11 @@ func (c Drives) GetItemIDsInContainer( return m, nil } -// --------------------------------------------------------------------------- - // --------------------------------------------------------------------------- // delta item pager // --------------------------------------------------------------------------- -type DriveItemDeltaEnumerator interface { - GetPage(context.Context) (DeltaPageLinker, error) - SetNext(nextLink string) - Reset() - ValuesIn(DeltaPageLinker) ([]models.DriveItemable, error) -} - -var _ DriveItemDeltaEnumerator = &DriveItemDeltaPageCtrl{} +var _ DeltaPager[models.DriveItemable] = &DriveItemDeltaPageCtrl{} type DriveItemDeltaPageCtrl struct { gs graph.Servicer @@ -198,7 +189,7 @@ func (p *DriveItemDeltaPageCtrl) SetNext(link string) { p.builder = drives.NewItemItemsItemDeltaRequestBuilder(link, p.gs.Adapter()) } -func (p *DriveItemDeltaPageCtrl) Reset() { +func (p *DriveItemDeltaPageCtrl) Reset(context.Context) { p.builder = p.gs.Client(). Drives(). ByDriveId(p.driveID). @@ -207,7 +198,7 @@ func (p *DriveItemDeltaPageCtrl) Reset() { Delta() } -func (p *DriveItemDeltaPageCtrl) ValuesIn(l DeltaPageLinker) ([]models.DriveItemable, error) { +func (p *DriveItemDeltaPageCtrl) ValuesIn(l PageLinker) ([]models.DriveItemable, error) { return getValues[models.DriveItemable](l) } @@ -215,7 +206,7 @@ func (p *DriveItemDeltaPageCtrl) ValuesIn(l DeltaPageLinker) ([]models.DriveItem // user's drives pager // --------------------------------------------------------------------------- -var _ DrivePager = &userDrivePager{} +var _ Pager[models.Driveable] = &userDrivePager{} type userDrivePager struct { userID string @@ -305,7 +296,7 @@ func (p *userDrivePager) ValuesIn(l PageLinker) ([]models.Driveable, error) { // site's libraries pager // --------------------------------------------------------------------------- -var _ DrivePager = &siteDrivePager{} +var _ Pager[models.Driveable] = &siteDrivePager{} type siteDrivePager struct { gs graph.Servicer @@ -367,17 +358,10 @@ func (p *siteDrivePager) ValuesIn(l PageLinker) ([]models.Driveable, error) { // drive pager // --------------------------------------------------------------------------- -// DrivePager pages through different types of drive owners -type DrivePager interface { - GetPage(context.Context) (PageLinker, error) - SetNext(nextLink string) - ValuesIn(PageLinker) ([]models.Driveable, error) -} - // GetAllDrives fetches all drives for the given pager func GetAllDrives( ctx context.Context, - pager DrivePager, + pager Pager[models.Driveable], retry bool, maxRetryCount int, ) ([]models.Driveable, error) { diff --git a/src/pkg/services/m365/api/events.go b/src/pkg/services/m365/api/events.go index 43b73810f..2bc1392dc 100644 --- a/src/pkg/services/m365/api/events.go +++ b/src/pkg/services/m365/api/events.go @@ -91,13 +91,10 @@ func (c Events) DeleteContainer( return nil } -// prefer GetContainerByID where possible. -// use this only in cases where the models.Calendarable -// is required. -func (c Events) GetCalendar( +func (c Events) GetContainerByID( ctx context.Context, userID, containerID string, -) (models.Calendarable, error) { +) (graph.Container, error) { config := &users.ItemCalendarsCalendarItemRequestBuilderGetRequestConfiguration{ QueryParameters: &users.ItemCalendarsCalendarItemRequestBuilderGetQueryParameters{ Select: idAnd("name", "owner"), @@ -115,20 +112,7 @@ func (c Events) GetCalendar( return nil, graph.Stack(ctx, err) } - return resp, nil -} - -// interface-compliant wrapper of GetCalendar -func (c Events) GetContainerByID( - ctx context.Context, - userID, containerID string, -) (graph.Container, error) { - cal, err := c.GetCalendar(ctx, userID, containerID) - if err != nil { - return nil, err - } - - return graph.CalendarDisplayable{Calendarable: cal}, nil + return graph.CalendarDisplayable{Calendarable: resp}, nil } // GetContainerByName fetches a calendar by name diff --git a/src/pkg/services/m365/api/events_pager.go b/src/pkg/services/m365/api/events_pager.go index 2874d37e5..55e227d58 100644 --- a/src/pkg/services/m365/api/events_pager.go +++ b/src/pkg/services/m365/api/events_pager.go @@ -173,7 +173,7 @@ func (c Events) GetItemsInContainerByCollisionKey( // item ID pager // --------------------------------------------------------------------------- -var _ itemIDPager = &eventIDPager{} +var _ DeltaPager[getIDAndAddtler] = &eventIDPager{} type eventIDPager struct { gs graph.Servicer @@ -185,7 +185,7 @@ func (c Events) NewEventIDsPager( ctx context.Context, userID, containerID string, immutableIDs bool, -) (itemIDPager, error) { +) (DeltaPager[getIDAndAddtler], error) { options := &users.ItemCalendarsItemEventsRequestBuilderGetRequestConfiguration{ Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize), preferImmutableIDs(immutableIDs)), QueryParameters: &users.ItemCalendarsItemEventsRequestBuilderGetQueryParameters{ @@ -204,7 +204,7 @@ func (c Events) NewEventIDsPager( return &eventIDPager{c.Stable, builder, options}, nil } -func (p *eventIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) { +func (p *eventIDPager) GetPage(ctx context.Context) (DeltaPageLinker, error) { resp, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) @@ -213,14 +213,14 @@ func (p *eventIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) { return EmptyDeltaLinker[models.Eventable]{PageLinkValuer: resp}, nil } -func (p *eventIDPager) setNext(nextLink string) { +func (p *eventIDPager) SetNext(nextLink string) { p.builder = users.NewItemCalendarsItemEventsRequestBuilder(nextLink, p.gs.Adapter()) } // non delta pagers don't need reset -func (p *eventIDPager) reset(context.Context) {} +func (p *eventIDPager) Reset(context.Context) {} -func (p *eventIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) { +func (p *eventIDPager) ValuesIn(pl PageLinker) ([]getIDAndAddtler, error) { return toValues[models.Eventable](pl) } @@ -228,7 +228,7 @@ func (p *eventIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) { // delta item ID pager // --------------------------------------------------------------------------- -var _ itemIDPager = &eventDeltaIDPager{} +var _ DeltaPager[getIDAndAddtler] = &eventDeltaIDPager{} type eventDeltaIDPager struct { gs graph.Servicer @@ -242,7 +242,7 @@ func (c Events) NewEventDeltaIDsPager( ctx context.Context, userID, containerID, oldDelta string, immutableIDs bool, -) (itemIDPager, error) { +) (DeltaPager[getIDAndAddtler], error) { options := &users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration{ Headers: newPreferHeaders(preferPageSize(c.options.DeltaPageSize), preferImmutableIDs(immutableIDs)), QueryParameters: &users.ItemCalendarsItemEventsDeltaRequestBuilderGetQueryParameters{ @@ -281,7 +281,7 @@ func getEventDeltaBuilder( return builder } -func (p *eventDeltaIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) { +func (p *eventDeltaIDPager) GetPage(ctx context.Context) (DeltaPageLinker, error) { resp, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) @@ -290,15 +290,15 @@ func (p *eventDeltaIDPager) getPage(ctx context.Context) (DeltaPageLinker, error return resp, nil } -func (p *eventDeltaIDPager) setNext(nextLink string) { +func (p *eventDeltaIDPager) SetNext(nextLink string) { p.builder = users.NewItemCalendarsItemEventsDeltaRequestBuilder(nextLink, p.gs.Adapter()) } -func (p *eventDeltaIDPager) reset(ctx context.Context) { +func (p *eventDeltaIDPager) Reset(ctx context.Context) { p.builder = getEventDeltaBuilder(ctx, p.gs, p.userID, p.containerID, p.options) } -func (p *eventDeltaIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) { +func (p *eventDeltaIDPager) ValuesIn(pl PageLinker) ([]getIDAndAddtler, error) { return toValues[models.Eventable](pl) } diff --git a/src/pkg/services/m365/api/item_pager.go b/src/pkg/services/m365/api/item_pager.go index 4cb272d51..285fb0e67 100644 --- a/src/pkg/services/m365/api/item_pager.go +++ b/src/pkg/services/m365/api/item_pager.go @@ -16,11 +16,31 @@ import ( // common interfaces // --------------------------------------------------------------------------- -// TODO(keepers): replace all matching uses of GetPage with this. +type DeltaPager[T any] interface { + DeltaGetPager + Resetter + SetNextLinker + ValuesInPageLinker[T] +} + +type Pager[T any] interface { + GetPager + SetNextLinker + ValuesInPageLinker[T] +} + type DeltaGetPager interface { GetPage(context.Context) (DeltaPageLinker, error) } +type GetPager interface { + GetPage(context.Context) (PageLinker, error) +} + +type Valuer[T any] interface { + GetValue() []T +} + type ValuesInPageLinker[T any] interface { ValuesIn(PageLinker) ([]T, error) } @@ -34,10 +54,19 @@ type DeltaPageLinker interface { GetOdataDeltaLink() *string } +type PageLinkValuer[T any] interface { + PageLinker + Valuer[T] +} + type SetNextLinker interface { SetNext(nextLink string) } +type Resetter interface { + Reset(context.Context) +} + // --------------------------------------------------------------------------- // common funcs // --------------------------------------------------------------------------- @@ -55,15 +84,6 @@ func NextAndDeltaLink(pl DeltaPageLinker) (string, string) { return NextLink(pl), ptr.Val(pl.GetOdataDeltaLink()) } -type Valuer[T any] interface { - GetValue() []T -} - -type PageLinkValuer[T any] interface { - PageLinker - Valuer[T] -} - // EmptyDeltaLinker is used to convert PageLinker to DeltaPageLinker type EmptyDeltaLinker[T any] struct { PageLinkValuer[T] @@ -148,19 +168,6 @@ func toValues[T any](a any) ([]getIDAndAddtler, error) { return r, nil } -type itemIDPager interface { - // getPage get a page with the specified options from graph - getPage(context.Context) (DeltaPageLinker, error) - // setNext is used to pass in the next url got from graph - setNext(string) - // reset is used to clear delta url in delta pagers. When - // reset is called, we reset the state(delta url) that we - // currently have and start a new delta query without the token. - reset(context.Context) - // valuesIn gets us the values in a page - valuesIn(PageLinker) ([]getIDAndAddtler, error) -} - type getIDAndAddtler interface { GetId() *string GetAdditionalData() map[string]any @@ -169,13 +176,13 @@ type getIDAndAddtler interface { func getAddedAndRemovedItemIDs( ctx context.Context, service graph.Servicer, - pager itemIDPager, - deltaPager itemIDPager, + pager DeltaPager[getIDAndAddtler], + deltaPager DeltaPager[getIDAndAddtler], oldDelta string, canMakeDeltaQueries bool, ) ([]string, []string, DeltaUpdate, error) { var ( - pgr itemIDPager + pgr DeltaPager[getIDAndAddtler] resetDelta bool ) @@ -204,7 +211,7 @@ func getAddedAndRemovedItemIDs( } // reset deltaPager - pgr.reset(ctx) + pgr.Reset(ctx) added, removed, deltaURL, err = getItemsAddedAndRemovedFromContainer(ctx, pgr) if err != nil { @@ -217,7 +224,7 @@ func getAddedAndRemovedItemIDs( // generic controller for retrieving all item ids in a container. func getItemsAddedAndRemovedFromContainer( ctx context.Context, - pager itemIDPager, + pager DeltaPager[getIDAndAddtler], ) ([]string, []string, string, error) { var ( addedIDs = []string{} @@ -229,14 +236,14 @@ func getItemsAddedAndRemovedFromContainer( for { // get the next page of data, check for standard errors - resp, err := pager.getPage(ctx) + resp, err := pager.GetPage(ctx) if err != nil { return nil, nil, deltaURL, graph.Stack(ctx, err) } // each category type responds with a different interface, but all // of them comply with GetValue, which is where we'll get our item data. - items, err := pager.valuesIn(resp) + items, err := pager.ValuesIn(resp) if err != nil { return nil, nil, "", graph.Stack(ctx, err) } @@ -278,7 +285,7 @@ func getItemsAddedAndRemovedFromContainer( break } - pager.setNext(nextLink) + pager.SetNext(nextLink) } logger.Ctx(ctx).Infow("completed enumeration", "count", itemCount) diff --git a/src/pkg/services/m365/api/item_pager_test.go b/src/pkg/services/m365/api/item_pager_test.go index 84b28b231..4b86b1600 100644 --- a/src/pkg/services/m365/api/item_pager_test.go +++ b/src/pkg/services/m365/api/item_pager_test.go @@ -95,7 +95,7 @@ func (p *testPager) setNext(nextLink string) {} // mock id pager -var _ itemIDPager = &testIDsPager{} +var _ DeltaPager[getIDAndAddtler] = &testIDsPager{} type testIDsPager struct { t *testing.T @@ -105,7 +105,7 @@ type testIDsPager struct { needsReset bool } -func (p *testIDsPager) getPage(ctx context.Context) (DeltaPageLinker, error) { +func (p *testIDsPager) GetPage(ctx context.Context) (DeltaPageLinker, error) { if p.errorCode != "" { ierr := odataerrors.NewMainError() ierr.SetCode(&p.errorCode) @@ -118,8 +118,8 @@ func (p *testIDsPager) getPage(ctx context.Context) (DeltaPageLinker, error) { return testPage{}, nil } -func (p *testIDsPager) setNext(string) {} -func (p *testIDsPager) reset(context.Context) { +func (p *testIDsPager) SetNext(string) {} +func (p *testIDsPager) Reset(context.Context) { if !p.needsReset { require.Fail(p.t, "reset should not be called") } @@ -128,7 +128,7 @@ func (p *testIDsPager) reset(context.Context) { p.errorCode = "" } -func (p *testIDsPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) { +func (p *testIDsPager) ValuesIn(pl PageLinker) ([]getIDAndAddtler, error) { items := []getIDAndAddtler{} for _, id := range p.added { @@ -208,15 +208,21 @@ func (suite *ItemPagerUnitSuite) TestEnumerateItems() { func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() { tests := []struct { - name string - pagerGetter func(*testing.T, context.Context, graph.Servicer, string, string, bool) (itemIDPager, error) + name string + pagerGetter func( + *testing.T, + context.Context, + graph.Servicer, + string, string, + bool, + ) (DeltaPager[getIDAndAddtler], error) deltaPagerGetter func( *testing.T, context.Context, graph.Servicer, string, string, string, bool, - ) (itemIDPager, error) + ) (DeltaPager[getIDAndAddtler], error) added []string removed []string deltaUpdate DeltaUpdate @@ -232,7 +238,7 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() { user string, directory string, immutableIDs bool, - ) (itemIDPager, error) { + ) (DeltaPager[getIDAndAddtler], error) { // this should not be called return nil, assert.AnError }, @@ -244,7 +250,7 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() { directory string, delta string, immutableIDs bool, - ) (itemIDPager, error) { + ) (DeltaPager[getIDAndAddtler], error) { return &testIDsPager{ t: t, added: []string{"uno", "dos"}, @@ -265,7 +271,7 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() { user string, directory string, immutableIDs bool, - ) (itemIDPager, error) { + ) (DeltaPager[getIDAndAddtler], error) { // this should not be called return nil, assert.AnError }, @@ -277,7 +283,7 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() { directory string, delta string, immutableIDs bool, - ) (itemIDPager, error) { + ) (DeltaPager[getIDAndAddtler], error) { return &testIDsPager{ t: t, added: []string{"uno", "dos"}, @@ -299,7 +305,7 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() { user string, directory string, immutableIDs bool, - ) (itemIDPager, error) { + ) (DeltaPager[getIDAndAddtler], error) { // this should not be called return nil, assert.AnError }, @@ -311,7 +317,7 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() { directory string, delta string, immutableIDs bool, - ) (itemIDPager, error) { + ) (DeltaPager[getIDAndAddtler], error) { return &testIDsPager{ t: t, added: []string{"uno", "dos"}, @@ -335,7 +341,7 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() { user string, directory string, immutableIDs bool, - ) (itemIDPager, error) { + ) (DeltaPager[getIDAndAddtler], error) { return &testIDsPager{ t: t, added: []string{"uno", "dos"}, @@ -350,7 +356,7 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() { directory string, delta string, immutableIDs bool, - ) (itemIDPager, error) { + ) (DeltaPager[getIDAndAddtler], error) { return &testIDsPager{errorCode: "ErrorQuotaExceeded"}, nil }, added: []string{"uno", "dos"}, diff --git a/src/pkg/services/m365/api/mail.go b/src/pkg/services/m365/api/mail.go index f4201ce5b..14762a192 100644 --- a/src/pkg/services/m365/api/mail.go +++ b/src/pkg/services/m365/api/mail.go @@ -41,46 +41,6 @@ type Mail struct { // containers // --------------------------------------------------------------------------- -// CreateMailFolder makes a mail folder iff a folder of the same name does not exist -// Reference: https://docs.microsoft.com/en-us/graph/api/user-post-mailfolders?view=graph-rest-1.0&tabs=http -func (c Mail) CreateMailFolder( - ctx context.Context, - userID, containerName string, -) (models.MailFolderable, error) { - isHidden := false - body := models.NewMailFolder() - body.SetDisplayName(&containerName) - body.SetIsHidden(&isHidden) - - mdl, err := c.Stable.Client(). - Users(). - ByUserId(userID). - MailFolders(). - Post(ctx, body, nil) - if err != nil { - return nil, graph.Wrap(ctx, err, "creating mail folder") - } - - return mdl, nil -} - -func (c Mail) DeleteMailFolder( - ctx context.Context, - userID, id string, -) error { - err := c.Stable.Client(). - Users(). - ByUserId(userID). - MailFolders(). - ByMailFolderId(id). - Delete(ctx, nil) - if err != nil { - return graph.Wrap(ctx, err, "deleting mail folder") - } - - return nil -} - func (c Mail) CreateContainer( ctx context.Context, userID, parentContainerID, containerName string, @@ -131,13 +91,10 @@ func (c Mail) DeleteContainer( return nil } -// prefer GetContainerByID where possible. -// use this only in cases where the models.MailFolderable -// is required. -func (c Mail) GetFolder( +func (c Mail) GetContainerByID( ctx context.Context, userID, containerID string, -) (models.MailFolderable, error) { +) (graph.Container, error) { config := &users.ItemMailFoldersMailFolderItemRequestBuilderGetRequestConfiguration{ QueryParameters: &users.ItemMailFoldersMailFolderItemRequestBuilderGetQueryParameters{ Select: idAnd(displayName, parentFolderID), @@ -158,14 +115,6 @@ func (c Mail) GetFolder( return resp, nil } -// interface-compliant wrapper of GetFolder -func (c Mail) GetContainerByID( - ctx context.Context, - userID, containerID string, -) (graph.Container, error) { - return c.GetFolder(ctx, userID, containerID) -} - // GetContainerByName fetches a folder by name func (c Mail) GetContainerByName( ctx context.Context, diff --git a/src/pkg/services/m365/api/mail_pager.go b/src/pkg/services/m365/api/mail_pager.go index 0648a906c..634a89095 100644 --- a/src/pkg/services/m365/api/mail_pager.go +++ b/src/pkg/services/m365/api/mail_pager.go @@ -174,7 +174,7 @@ func (p *mailPageCtrl) setNext(nextLink string) { // item ID pager // --------------------------------------------------------------------------- -var _ itemIDPager = &mailIDPager{} +var _ DeltaPager[getIDAndAddtler] = &mailIDPager{} type mailIDPager struct { gs graph.Servicer @@ -186,7 +186,7 @@ func (c Mail) NewMailIDsPager( ctx context.Context, userID, containerID string, immutableIDs bool, -) itemIDPager { +) DeltaPager[getIDAndAddtler] { config := &users.ItemMailFoldersItemMessagesRequestBuilderGetRequestConfiguration{ QueryParameters: &users.ItemMailFoldersItemMessagesRequestBuilderGetQueryParameters{ Select: idAnd("isRead"), @@ -206,7 +206,7 @@ func (c Mail) NewMailIDsPager( return &mailIDPager{c.Stable, builder, config} } -func (p *mailIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) { +func (p *mailIDPager) GetPage(ctx context.Context) (DeltaPageLinker, error) { page, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) @@ -215,14 +215,14 @@ func (p *mailIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) { return EmptyDeltaLinker[models.Messageable]{PageLinkValuer: page}, nil } -func (p *mailIDPager) setNext(nextLink string) { +func (p *mailIDPager) SetNext(nextLink string) { p.builder = users.NewItemMailFoldersItemMessagesRequestBuilder(nextLink, p.gs.Adapter()) } // non delta pagers don't have reset -func (p *mailIDPager) reset(context.Context) {} +func (p *mailIDPager) Reset(context.Context) {} -func (p *mailIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) { +func (p *mailIDPager) ValuesIn(pl PageLinker) ([]getIDAndAddtler, error) { return toValues[models.Messageable](pl) } @@ -272,7 +272,7 @@ func (c Mail) GetItemIDsInContainer( // delta item ID pager // --------------------------------------------------------------------------- -var _ itemIDPager = &mailDeltaIDPager{} +var _ DeltaPager[getIDAndAddtler] = &mailDeltaIDPager{} type mailDeltaIDPager struct { gs graph.Servicer @@ -304,7 +304,7 @@ func (c Mail) NewMailDeltaIDsPager( ctx context.Context, userID, containerID, oldDelta string, immutableIDs bool, -) itemIDPager { +) DeltaPager[getIDAndAddtler] { config := &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration{ QueryParameters: &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetQueryParameters{ Select: idAnd("isRead"), @@ -324,7 +324,7 @@ func (c Mail) NewMailDeltaIDsPager( return &mailDeltaIDPager{c.Stable, userID, containerID, builder, config} } -func (p *mailDeltaIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) { +func (p *mailDeltaIDPager) GetPage(ctx context.Context) (DeltaPageLinker, error) { page, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) @@ -333,11 +333,11 @@ func (p *mailDeltaIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) return page, nil } -func (p *mailDeltaIDPager) setNext(nextLink string) { +func (p *mailDeltaIDPager) SetNext(nextLink string) { p.builder = users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(nextLink, p.gs.Adapter()) } -func (p *mailDeltaIDPager) reset(ctx context.Context) { +func (p *mailDeltaIDPager) Reset(ctx context.Context) { p.builder = p.gs. Client(). Users(). @@ -348,7 +348,7 @@ func (p *mailDeltaIDPager) reset(ctx context.Context) { Delta() } -func (p *mailDeltaIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) { +func (p *mailDeltaIDPager) ValuesIn(pl PageLinker) ([]getIDAndAddtler, error) { return toValues[models.Messageable](pl) } diff --git a/src/pkg/services/m365/api/mail_test.go b/src/pkg/services/m365/api/mail_test.go index 5c0f1ccd8..74a4d57b7 100644 --- a/src/pkg/services/m365/api/mail_test.go +++ b/src/pkg/services/m365/api/mail_test.go @@ -383,7 +383,7 @@ func (suite *MailAPIIntgSuite) TestMail_RestoreLargeAttachment() { folderName := testdata.DefaultRestoreConfig("maillargeattachmenttest").Location msgs := suite.its.ac.Mail() - mailfolder, err := msgs.CreateMailFolder(ctx, userID, folderName) + mailfolder, err := msgs.CreateContainer(ctx, userID, api.MsgFolderRoot, folderName) require.NoError(t, err, clues.ToCore(err)) msg := models.NewMessage() diff --git a/src/pkg/services/m365/api/mock/drive_pager.go b/src/pkg/services/m365/api/mock/drive_pager.go deleted file mode 100644 index 2551e971b..000000000 --- a/src/pkg/services/m365/api/mock/drive_pager.go +++ /dev/null @@ -1,56 +0,0 @@ -package mock - -import ( - "context" - - "github.com/alcionai/clues" - "github.com/microsoftgraph/msgraph-sdk-go/models" - - "github.com/alcionai/corso/src/pkg/services/m365/api" -) - -type PageLink struct { - Link *string -} - -func (pl *PageLink) GetOdataNextLink() *string { - return pl.Link -} - -type PagerResult struct { - Drives []models.Driveable - NextLink *string - Err error -} - -type DrivePager struct { - ToReturn []PagerResult - GetIdx int -} - -func (p *DrivePager) GetPage(context.Context) (api.PageLinker, error) { - if len(p.ToReturn) <= p.GetIdx { - return nil, clues.New("ToReturn index out of bounds") - } - - idx := p.GetIdx - p.GetIdx++ - - return &PageLink{p.ToReturn[idx].NextLink}, p.ToReturn[idx].Err -} - -func (p *DrivePager) SetNext(string) {} - -func (p *DrivePager) ValuesIn(api.PageLinker) ([]models.Driveable, error) { - idx := p.GetIdx - if idx > 0 { - // Return values lag by one since we increment in GetPage(). - idx-- - } - - if len(p.ToReturn) <= idx { - return nil, clues.New("ToReturn index out of bounds") - } - - return p.ToReturn[idx].Drives, nil -} diff --git a/src/pkg/services/m365/api/mock/pager.go b/src/pkg/services/m365/api/mock/pager.go new file mode 100644 index 000000000..9fd8749dd --- /dev/null +++ b/src/pkg/services/m365/api/mock/pager.go @@ -0,0 +1,113 @@ +package mock + +import ( + "context" + + "github.com/alcionai/clues" + + "github.com/alcionai/corso/src/pkg/services/m365/api" +) + +type DeltaNextLinks struct { + Next *string + Delta *string +} + +func (dnl *DeltaNextLinks) GetOdataNextLink() *string { + return dnl.Next +} + +func (dnl *DeltaNextLinks) GetOdataDeltaLink() *string { + return dnl.Delta +} + +type PagerResult[T any] struct { + Values []T + NextLink *string + DeltaLink *string + Err error +} + +// --------------------------------------------------------------------------- +// non-delta pager +// --------------------------------------------------------------------------- + +type Pager[T any] struct { + ToReturn []PagerResult[T] + getIdx int +} + +func (p *Pager[T]) GetPage(context.Context) (api.PageLinker, error) { + if len(p.ToReturn) <= p.getIdx { + return nil, clues.New("index out of bounds"). + With("index", p.getIdx, "values", p.ToReturn) + } + + idx := p.getIdx + p.getIdx++ + + link := DeltaNextLinks{Next: p.ToReturn[idx].NextLink} + + return &link, p.ToReturn[idx].Err +} + +func (p *Pager[T]) SetNext(string) {} + +func (p *Pager[T]) ValuesIn(api.PageLinker) ([]T, error) { + idx := p.getIdx + if idx > 0 { + // Return values lag by one since we increment in GetPage(). + idx-- + } + + if len(p.ToReturn) <= idx { + return nil, clues.New("index out of bounds"). + With("index", idx, "values", p.ToReturn) + } + + return p.ToReturn[idx].Values, nil +} + +// --------------------------------------------------------------------------- +// delta pager +// --------------------------------------------------------------------------- + +type DeltaPager[T any] struct { + ToReturn []PagerResult[T] + getIdx int +} + +func (p *DeltaPager[T]) GetPage(context.Context) (api.DeltaPageLinker, error) { + if len(p.ToReturn) <= p.getIdx { + return nil, clues.New("index out of bounds"). + With("index", p.getIdx, "values", p.ToReturn) + } + + idx := p.getIdx + p.getIdx++ + + link := DeltaNextLinks{ + Next: p.ToReturn[idx].NextLink, + Delta: p.ToReturn[idx].DeltaLink, + } + + return &link, p.ToReturn[idx].Err +} + +func (p *DeltaPager[T]) SetNext(string) {} +func (p *DeltaPager[T]) Reset(context.Context) {} + +func (p *DeltaPager[T]) ValuesIn(api.PageLinker) ([]T, error) { + idx := p.getIdx + if idx > 0 { + // Return values lag by one since we increment in GetPage(). + idx-- + } + + if len(p.ToReturn) <= idx { + return nil, clues.New("index out of bounds"). + With("index", idx, "values", p.ToReturn) + } + + return p.ToReturn[idx].Values, nil +}