Skip to content

Commit

Permalink
allow creation of restore paths for sharepoint lists (#4908)
Browse files Browse the repository at this point in the history
this allows creation of restore paths for sharepoint lists.
Below changes got lost during PR merges:
- #4855

#### Does this PR need a docs update or release note?
- [x] ⛔ No

#### Type of change

<!--- Please check the type of change your PR introduces: --->
- [x] 🐛 Bugfix

#### Issue(s)
#4754 

#### Test Plan

<!-- How will this be tested prior to merging.-->
- [x] 💪 Manual
- [x] ⚡ Unit test
- [x] 💚 E2E
  • Loading branch information
HiteshRepo authored Dec 21, 2023
1 parent 0ead1b1 commit d015ea2
Show file tree
Hide file tree
Showing 10 changed files with 332 additions and 122 deletions.
69 changes: 0 additions & 69 deletions src/internal/m365/collection/site/collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/alcionai/clues"
kioser "github.com/microsoft/kiota-serialization-json-go"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/microsoftgraph/msgraph-sdk-go/sites"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
Expand All @@ -24,7 +23,6 @@ import (
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/control/testdata"
"github.com/alcionai/corso/src/pkg/count"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/path"
Expand Down Expand Up @@ -336,70 +334,3 @@ func (suite *SharePointCollectionSuite) TestCollection_streamItems() {
})
}
}

// TestRestoreListCollection verifies Graph Restore API for the List Collection
func (suite *SharePointCollectionSuite) TestListCollection_Restore() {
t := suite.T()
// https://github.com/microsoftgraph/msgraph-sdk-go/issues/490
t.Skip("disabled until upstream issue with list restore is fixed.")

ctx, flush := tester.NewContext(t)
defer flush()

service := createTestService(t, suite.creds)
listing := spMock.ListDefault("Mock List")
testName := "MockListing"
listing.SetDisplayName(&testName)
byteArray, err := service.Serialize(listing)
require.NoError(t, err, clues.ToCore(err))

info := &details.SharePointInfo{
ItemName: testName,
}

listData, err := data.NewPrefetchedItemWithInfo(
io.NopCloser(bytes.NewReader(byteArray)),
testName,
details.ItemInfo{SharePoint: info})
require.NoError(t, err, clues.ToCore(err))

destName := testdata.DefaultRestoreConfig("").Location

lrh := NewListsRestoreHandler(suite.siteID, suite.ac.Lists())
deets, err := restoreListItem(ctx, lrh, listData, suite.siteID, destName)
assert.NoError(t, err, clues.ToCore(err))
t.Logf("List created: %s\n", deets.SharePoint.ItemName)

// Clean-Up
var (
builder = service.Client().Sites().BySiteId(suite.siteID).Lists()
isFound bool
deleteID string
)

for {
resp, err := builder.Get(ctx, nil)
assert.NoError(t, err, "getting site lists", clues.ToCore(err))

for _, temp := range resp.GetValue() {
if ptr.Val(temp.GetDisplayName()) == deets.SharePoint.ItemName {
isFound = true
deleteID = ptr.Val(temp.GetId())

break
}
}
// Get Next Link
link, ok := ptr.ValOK(resp.GetOdataNextLink())
if !ok {
break
}

builder = sites.NewItemListsRequestBuilder(link, service.Adapter())
}

if isFound {
err := DeleteList(ctx, service, suite.siteID, deleteID)
assert.NoError(t, err, clues.ToCore(err))
}
}
23 changes: 0 additions & 23 deletions src/internal/m365/collection/site/lists.go

This file was deleted.

5 changes: 5 additions & 0 deletions src/internal/m365/collection/site/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ func RestoreListCollection(
itemData,
siteID,
restoreContainerName)
if err != nil &&
errors.Is(err, api.ErrCannotCreateWebTemplateExtension) {
continue
}

if err != nil {
el.AddRecoverable(ctx, err)
continue
Expand Down
184 changes: 184 additions & 0 deletions src/internal/m365/collection/site/restore_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package site

import (
"bytes"
"context"
"fmt"
"io"
"testing"

"github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"

"github.com/alcionai/corso/src/internal/common/ptr"
"github.com/alcionai/corso/src/internal/common/readers"
"github.com/alcionai/corso/src/internal/data"
dataMock "github.com/alcionai/corso/src/internal/data/mock"
spMock "github.com/alcionai/corso/src/internal/m365/service/sharepoint/mock"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/internal/tester/tconfig"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/control/testdata"
"github.com/alcionai/corso/src/pkg/count"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
)

type SharePointRestoreSuite struct {
tester.Suite
siteID string
creds account.M365Config
ac api.Client
}

func (suite *SharePointRestoreSuite) SetupSuite() {
t := suite.T()

ctx, flush := tester.NewContext(t)
defer flush()
graph.InitializeConcurrencyLimiter(ctx, false, 4)

suite.siteID = tconfig.M365SiteID(t)
a := tconfig.NewM365Account(t)
m365, err := a.M365Config()
require.NoError(t, err, clues.ToCore(err))

suite.creds = m365

ac, err := api.NewClient(
m365,
control.DefaultOptions(),
count.New())
require.NoError(t, err, clues.ToCore(err))

suite.ac = ac
}

func TestSharePointRestoreSuite(t *testing.T) {
suite.Run(t, &SharePointRestoreSuite{
Suite: tester.NewIntegrationSuite(
t,
[][]string{tconfig.M365AcctCredEnvs}),
})
}

// TestRestoreListCollection verifies Graph Restore API for the List Collection
func (suite *SharePointRestoreSuite) TestListCollection_Restore() {
t := suite.T()

ctx, flush := tester.NewContext(t)
defer flush()

testName, lrh, destName, mockData := setupDependencies(
suite,
suite.ac,
suite.siteID,
suite.creds,
"genericList")

deets, err := restoreListItem(ctx, lrh, mockData, suite.siteID, destName)
require.NoError(t, err, clues.ToCore(err))
assert.Equal(t, fmt.Sprintf("%s_%s", destName, testName), deets.SharePoint.ItemName)

// Clean-Up
deleteList(ctx, t, suite.siteID, lrh, deets)
}

func (suite *SharePointRestoreSuite) TestListCollection_Restore_invalidListTemplate() {
t := suite.T()

ctx, flush := tester.NewContext(t)
defer flush()

_, lrh, destName, mockData := setupDependencies(
suite,
suite.ac,
suite.siteID,
suite.creds,
api.WebTemplateExtensionsListTemplateName)

_, err := restoreListItem(ctx, lrh, mockData, suite.siteID, destName)
require.Error(t, err)
assert.Contains(t, err.Error(), api.ErrCannotCreateWebTemplateExtension.Error())
}

func deleteList(
ctx context.Context,
t *testing.T,
siteID string,
lrh listsRestoreHandler,
deets details.ItemInfo,
) {
var (
isFound bool
deleteID string
)

lists, err := lrh.ac.Client.
Lists().
GetLists(ctx, siteID, api.CallConfig{})
assert.NoError(t, err, "getting site lists", clues.ToCore(err))

for _, l := range lists {
if ptr.Val(l.GetDisplayName()) == deets.SharePoint.ItemName {
isFound = true
deleteID = ptr.Val(l.GetId())

break
}
}

if isFound {
err := lrh.DeleteList(ctx, deleteID)
assert.NoError(t, err, clues.ToCore(err))
}
}

func setupDependencies(
suite tester.Suite,
ac api.Client,
siteID string,
creds account.M365Config,
listTemplate string) (
string, listsRestoreHandler, string, *dataMock.Item,
) {
t := suite.T()
testName := "MockListing"

lrh := NewListsRestoreHandler(siteID, ac.Lists())

service := createTestService(t, creds)

listInfo := models.NewListInfo()
listInfo.SetTemplate(ptr.To(listTemplate))

listing := spMock.ListDefault("Mock List")
listing.SetDisplayName(&testName)
listing.SetList(listInfo)

byteArray, err := service.Serialize(listing)
require.NoError(t, err, clues.ToCore(err))

destName := testdata.DefaultRestoreConfig("").Location

listData, err := data.NewPrefetchedItemWithInfo(
io.NopCloser(bytes.NewReader(byteArray)),
testName,
details.ItemInfo{SharePoint: api.ListToSPInfo(listing)})
require.NoError(t, err, clues.ToCore(err))

r, err := readers.NewVersionedRestoreReader(listData.ToReader())
require.NoError(t, err)

mockData := &dataMock.Item{
ItemID: testName,
Reader: r,
}

return testName, lrh, destName, mockData
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ func makeRestorePathsForEntry(
// * OneDrive/SharePoint (needs drive information)
switch true {
case ent.Exchange != nil ||
(ent.Groups != nil && ent.Groups.ItemType == details.GroupsChannelMessage):
(ent.Groups != nil && ent.Groups.ItemType == details.GroupsChannelMessage) ||
(ent.SharePoint != nil && ent.SharePoint.ItemType == details.SharePointList):
// TODO(ashmrtn): Eventually make Events have it's own function to handle
// setting the restore destination properly.
res.RestorePath, err = basicLocationPath(repoRef, locRef)
Expand Down
Loading

0 comments on commit d015ea2

Please sign in to comment.