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:
parent
bf1b290e2a
commit
f742318319
@ -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())
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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"
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user