diff --git a/src/internal/m365/backup_test.go b/src/internal/m365/backup_test.go index c2938a36b..068d05891 100644 --- a/src/internal/m365/backup_test.go +++ b/src/internal/m365/backup_test.go @@ -13,6 +13,7 @@ import ( inMock "github.com/alcionai/corso/src/internal/common/idname/mock" "github.com/alcionai/corso/src/internal/m365/resource" "github.com/alcionai/corso/src/internal/m365/service/exchange" + odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts" "github.com/alcionai/corso/src/internal/m365/service/sharepoint" "github.com/alcionai/corso/src/internal/operations/inject" "github.com/alcionai/corso/src/internal/tester" @@ -473,6 +474,7 @@ func (suite *SPCollectionIntgSuite) TestCreateSharePointCollection_Lists() { type GroupsCollectionIntgSuite struct { tester.Suite connector *Controller + tenantID string user string } @@ -485,13 +487,21 @@ func TestGroupsCollectionIntgSuite(t *testing.T) { } func (suite *GroupsCollectionIntgSuite) SetupSuite() { - ctx, flush := tester.NewContext(suite.T()) + t := suite.T() + + ctx, flush := tester.NewContext(t) defer flush() - suite.connector = newController(ctx, suite.T(), resource.Sites, path.GroupsService) - suite.user = tconfig.M365UserID(suite.T()) + suite.connector = newController(ctx, t, resource.Sites, path.GroupsService) + suite.user = tconfig.M365UserID(t) - tester.LogTimeOfTest(suite.T()) + acct := tconfig.NewM365Account(t) + creds, err := acct.M365Config() + require.NoError(t, err, clues.ToCore(err)) + + suite.tenantID = creds.AzureTenantID + + tester.LogTimeOfTest(t) } func (suite *GroupsCollectionIntgSuite) TestCreateGroupsCollection_SharePoint() { @@ -535,14 +545,37 @@ func (suite *GroupsCollectionIntgSuite) TestCreateGroupsCollection_SharePoint() // but it should be more than one. assert.Greater(t, len(collections), 1) + // TODO(meain): Switch to using BuildMetadata + // https://github.com/alcionai/corso/pull/4184#discussion_r1316139701 + p, err := path.Builder{}.ToServiceCategoryMetadataPath( + suite.tenantID, + groupID, + path.GroupsService, + path.LibrariesCategory, + false) + require.NoError(t, err, clues.ToCore(err)) + + p, err = p.Append(false, odConsts.SitesPathDir) + require.NoError(t, err, clues.ToCore(err)) + + foundSitesMetadata := false + for _, coll := range collections { + sitesMetadataCollection := coll.FullPath().String() == p.String() + for object := range coll.Items(ctx, fault.New(true)) { + if object.ID() == "previouspath" && sitesMetadataCollection { + foundSitesMetadata = true + } + buf := &bytes.Buffer{} _, err := buf.ReadFrom(object.ToReader()) assert.NoError(t, err, "reading item", clues.ToCore(err)) } } + assert.True(t, foundSitesMetadata, "missing sites metadata") + status := ctrl.Wait() assert.NotZero(t, status.Successes) t.Log(status.String()) diff --git a/src/internal/m365/collection/drive/group_handler.go b/src/internal/m365/collection/drive/group_handler.go index 5a2438c21..91d627510 100644 --- a/src/internal/m365/collection/drive/group_handler.go +++ b/src/internal/m365/collection/drive/group_handler.go @@ -65,7 +65,7 @@ func (h groupBackupHandler) MetadataPathPrefix(tenantID string) (path.Path, erro p, err = p.Append(false, odConsts.SitesPathDir, h.siteID) if err != nil { - return nil, clues.Wrap(err, "appending sites to metadata path") + return nil, clues.Wrap(err, "appending site id to metadata path") } return p, nil @@ -86,6 +86,17 @@ func (h groupBackupHandler) CanonicalPath( ) } +func (h groupBackupHandler) SitePathPrefix(tenantID string) (path.Path, error) { + return path.Build( + tenantID, + h.groupID, + h.service, + path.LibrariesCategory, + false, + odConsts.SitesPathDir, + h.siteID) +} + func (h groupBackupHandler) IsAllPass() bool { return h.scope.IsAny(selectors.GroupsLibraryFolder) } diff --git a/src/internal/m365/collection/drive/group_handler_test.go b/src/internal/m365/collection/drive/group_handler_test.go index 44847e80e..ada9d77f8 100644 --- a/src/internal/m365/collection/drive/group_handler_test.go +++ b/src/internal/m365/collection/drive/group_handler_test.go @@ -49,6 +49,35 @@ func (suite *GroupBackupHandlerUnitSuite) TestPathPrefix() { } } +func (suite *GroupBackupHandlerUnitSuite) TestSitePathPrefix() { + tenantID, resourceOwner := "tenant", "resourceOwner" + + table := []struct { + name string + expect string + expectErr assert.ErrorAssertionFunc + }{ + { + name: "group", + expect: "tenant/groups/resourceOwner/libraries/sites/site-id", + expectErr: assert.NoError, + }, + } + for _, test := range table { + suite.Run(test.name, func() { + t := suite.T() + h := NewGroupBackupHandler(resourceOwner, "site-id", api.Drives{}, nil) + + result, err := h.SitePathPrefix(tenantID) + test.expectErr(t, err, clues.ToCore(err)) + + if result != nil { + assert.Equal(t, test.expect, result.String()) + } + }) + } +} + func (suite *GroupBackupHandlerUnitSuite) TestMetadataPathPrefix() { tenantID, resourceOwner := "tenant", "resourceOwner" diff --git a/src/internal/m365/service/groups/backup.go b/src/internal/m365/service/groups/backup.go index fa6361768..01e4f7e72 100644 --- a/src/internal/m365/service/groups/backup.go +++ b/src/internal/m365/service/groups/backup.go @@ -13,6 +13,7 @@ import ( "github.com/alcionai/corso/src/internal/m365/collection/groups" "github.com/alcionai/corso/src/internal/m365/collection/site" "github.com/alcionai/corso/src/internal/m365/graph" + odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts" "github.com/alcionai/corso/src/internal/m365/support" "github.com/alcionai/corso/src/internal/observe" "github.com/alcionai/corso/src/internal/operations/inject" @@ -41,6 +42,7 @@ func ProduceBackupCollections( categories = map[path.CategoryType]struct{}{} ssmb = prefixmatcher.NewStringSetBuilder() canUsePreviousBackup bool + sitesPreviousPaths = map[string]string{} ) ctx = clues.Add( @@ -78,15 +80,23 @@ func ProduceBackupCollections( Selector: bpc.Selector, } + bh := drive.NewGroupBackupHandler( + bpc.ProtectedResource.ID(), + ptr.Val(resp.GetId()), + ac.Drives(), + scope) + + cp, err := bh.SitePathPrefix(creds.AzureTenantID) + if err != nil { + return nil, nil, false, clues.Wrap(err, "getting canonical path") + } + + sitesPreviousPaths[ptr.Val(resp.GetId())] = cp.String() + dbcs, canUsePreviousBackup, err = site.CollectLibraries( ctx, sbpc, - drive.NewGroupBackupHandler( - bpc.ProtectedResource.ID(), - ptr.Val(resp.GetId()), - ac.Drives(), - scope, - ), + bh, creds.AzureTenantID, ssmb, su, @@ -133,5 +143,49 @@ func ProduceBackupCollections( collections = append(collections, baseCols...) } + // Add metadata about sites + md, err := getSitesMetadataCollection( + creds.AzureTenantID, + bpc.ProtectedResource.ID(), + sitesPreviousPaths, + su) + if err != nil { + return nil, nil, false, err + } + + collections = append(collections, md) + return collections, ssmb.ToReader(), canUsePreviousBackup, el.Failure() } + +func getSitesMetadataCollection( + tenantID, groupID string, + sites map[string]string, + su support.StatusUpdater, +) (data.BackupCollection, error) { + // TODO(meain): Switch to using BuildMetadata + // https://github.com/alcionai/corso/pull/4184#discussion_r1316139701 + p, err := path.Builder{}.ToServiceCategoryMetadataPath( + tenantID, + groupID, + path.GroupsService, + path.LibrariesCategory, + false) + if err != nil { + return nil, clues.Wrap(err, "making metadata path") + } + + p, err = p.Append(false, odConsts.SitesPathDir) + if err != nil { + return nil, clues.Wrap(err, "appending sites to metadata path") + } + + md, err := graph.MakeMetadataCollection( + p, + []graph.MetadataCollectionEntry{ + graph.NewMetadataEntry(graph.PreviousPathFileName, sites), + }, + su) + + return md, err +}