Add sites metadata in Groups backup (#4184)

Add sites metadata (previous paths) under `groupID/libraries/sites/previouspath`.

<!-- PR description-->

---

#### Does this PR need a docs update or release note?

- [ ]  Yes, it's included
- [ ] 🕐 Yes, but in a later PR
- [x]  No

#### Type of change

<!--- Please check the type of change your PR introduces: --->
- [x] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [ ] 🤖 Supportability/Tests
- [ ] 💻 CI/Deployment
- [ ] 🧹 Tech Debt/Cleanup

#### Issue(s)

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

#### Test Plan

<!-- How will this be tested prior to merging.-->
- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
Abin Simon 2023-09-07 10:29:31 +05:30 committed by GitHub
parent bf1b290e2a
commit f742318319
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 11 deletions

View File

@ -13,6 +13,7 @@ import (
inMock "github.com/alcionai/corso/src/internal/common/idname/mock" 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/resource"
"github.com/alcionai/corso/src/internal/m365/service/exchange" "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/m365/service/sharepoint"
"github.com/alcionai/corso/src/internal/operations/inject" "github.com/alcionai/corso/src/internal/operations/inject"
"github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/internal/tester"
@ -473,6 +474,7 @@ func (suite *SPCollectionIntgSuite) TestCreateSharePointCollection_Lists() {
type GroupsCollectionIntgSuite struct { type GroupsCollectionIntgSuite struct {
tester.Suite tester.Suite
connector *Controller connector *Controller
tenantID string
user string user string
} }
@ -485,13 +487,21 @@ func TestGroupsCollectionIntgSuite(t *testing.T) {
} }
func (suite *GroupsCollectionIntgSuite) SetupSuite() { func (suite *GroupsCollectionIntgSuite) SetupSuite() {
ctx, flush := tester.NewContext(suite.T()) t := suite.T()
ctx, flush := tester.NewContext(t)
defer flush() defer flush()
suite.connector = newController(ctx, suite.T(), resource.Sites, path.GroupsService) suite.connector = newController(ctx, t, resource.Sites, path.GroupsService)
suite.user = tconfig.M365UserID(suite.T()) 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() { func (suite *GroupsCollectionIntgSuite) TestCreateGroupsCollection_SharePoint() {
@ -535,14 +545,37 @@ func (suite *GroupsCollectionIntgSuite) TestCreateGroupsCollection_SharePoint()
// but it should be more than one. // but it should be more than one.
assert.Greater(t, len(collections), 1) 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 { for _, coll := range collections {
sitesMetadataCollection := coll.FullPath().String() == p.String()
for object := range coll.Items(ctx, fault.New(true)) { for object := range coll.Items(ctx, fault.New(true)) {
if object.ID() == "previouspath" && sitesMetadataCollection {
foundSitesMetadata = true
}
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
_, err := buf.ReadFrom(object.ToReader()) _, err := buf.ReadFrom(object.ToReader())
assert.NoError(t, err, "reading item", clues.ToCore(err)) assert.NoError(t, err, "reading item", clues.ToCore(err))
} }
} }
assert.True(t, foundSitesMetadata, "missing sites metadata")
status := ctrl.Wait() status := ctrl.Wait()
assert.NotZero(t, status.Successes) assert.NotZero(t, status.Successes)
t.Log(status.String()) t.Log(status.String())

View File

@ -65,7 +65,7 @@ func (h groupBackupHandler) MetadataPathPrefix(tenantID string) (path.Path, erro
p, err = p.Append(false, odConsts.SitesPathDir, h.siteID) p, err = p.Append(false, odConsts.SitesPathDir, h.siteID)
if err != nil { 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 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 { func (h groupBackupHandler) IsAllPass() bool {
return h.scope.IsAny(selectors.GroupsLibraryFolder) return h.scope.IsAny(selectors.GroupsLibraryFolder)
} }

View File

@ -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() { func (suite *GroupBackupHandlerUnitSuite) TestMetadataPathPrefix() {
tenantID, resourceOwner := "tenant", "resourceOwner" tenantID, resourceOwner := "tenant", "resourceOwner"

View File

@ -13,6 +13,7 @@ import (
"github.com/alcionai/corso/src/internal/m365/collection/groups" "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/collection/site"
"github.com/alcionai/corso/src/internal/m365/graph" "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/m365/support"
"github.com/alcionai/corso/src/internal/observe" "github.com/alcionai/corso/src/internal/observe"
"github.com/alcionai/corso/src/internal/operations/inject" "github.com/alcionai/corso/src/internal/operations/inject"
@ -41,6 +42,7 @@ func ProduceBackupCollections(
categories = map[path.CategoryType]struct{}{} categories = map[path.CategoryType]struct{}{}
ssmb = prefixmatcher.NewStringSetBuilder() ssmb = prefixmatcher.NewStringSetBuilder()
canUsePreviousBackup bool canUsePreviousBackup bool
sitesPreviousPaths = map[string]string{}
) )
ctx = clues.Add( ctx = clues.Add(
@ -78,15 +80,23 @@ func ProduceBackupCollections(
Selector: bpc.Selector, 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( dbcs, canUsePreviousBackup, err = site.CollectLibraries(
ctx, ctx,
sbpc, sbpc,
drive.NewGroupBackupHandler( bh,
bpc.ProtectedResource.ID(),
ptr.Val(resp.GetId()),
ac.Drives(),
scope,
),
creds.AzureTenantID, creds.AzureTenantID,
ssmb, ssmb,
su, su,
@ -133,5 +143,49 @@ func ProduceBackupCollections(
collections = append(collections, baseCols...) 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() 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
}