Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

relocates lists and associated relationship retrieval from M365 #4785

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 6 additions & 22 deletions src/cli/backup/sharepoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,12 @@ func validateSharePointBackupCreateFlags(sites, weburls, cats []string) error {
flags.SiteFN + " *")
}

allowedCats := utils.SharePointAllowedCategories()

for _, d := range cats {
if d != flags.DataLibraries && d != flags.DataPages {
if _, ok := allowedCats[d]; !ok {
return clues.New(
d + " is an unrecognized data type; either " + flags.DataLibraries + "or " + flags.DataPages)
d + " is an unrecognized data type; only " + flags.DataLibraries + " supported")
}
}

Expand All @@ -224,29 +226,11 @@ func sharePointBackupCreateSelectors(

sel := selectors.NewSharePointBackup(append(slices.Clone(sites), weburls...))

return addCategories(sel, cats), nil
return utils.AddCategories(sel, cats), nil
}

func includeAllSitesWithCategories(ins idname.Cacher, categories []string) *selectors.SharePointBackup {
return addCategories(selectors.NewSharePointBackup(ins.IDs()), categories)
}

func addCategories(sel *selectors.SharePointBackup, cats []string) *selectors.SharePointBackup {
// Issue #2631: Libraries are the only supported feature for SharePoint at this time.
if len(cats) == 0 {
sel.Include(sel.LibraryFolders(selectors.Any()))
}

for _, d := range cats {
switch d {
case flags.DataLibraries:
sel.Include(sel.LibraryFolders(selectors.Any()))
case flags.DataPages:
sel.Include(sel.Pages(selectors.Any()))
}
}

return sel
return utils.AddCategories(selectors.NewSharePointBackup(ins.IDs()), categories)
}

// ------------------------------------------------------------------------------------------------
Expand Down
300 changes: 297 additions & 3 deletions src/cli/backup/sharepoint_e2e_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package backup_test

import (
"context"
"fmt"
"strings"
"testing"

"github.com/alcionai/clues"
"github.com/google/uuid"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
Expand All @@ -22,12 +24,12 @@ import (
"github.com/alcionai/corso/src/pkg/config"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/selectors/testdata"
selTD "github.com/alcionai/corso/src/pkg/selectors/testdata"
storeTD "github.com/alcionai/corso/src/pkg/storage/testdata"
)

// ---------------------------------------------------------------------------
// tests with no prior backup
// tests that require no existing backups
// ---------------------------------------------------------------------------

type NoBackupSharePointE2ESuite struct {
Expand Down Expand Up @@ -79,6 +81,278 @@ func (suite *NoBackupSharePointE2ESuite) TestSharePointBackupListCmd_empty() {
assert.True(t, strings.HasSuffix(result, "No backups available\n"))
}

// ---------------------------------------------------------------------------
// tests with no prior backup
// ---------------------------------------------------------------------------

type BackupSharepointE2ESuite struct {
tester.Suite
dpnd dependencies
its intgTesterSetup
}

func TestBackupSharepointE2ESuite(t *testing.T) {
suite.Run(t, &BackupSharepointE2ESuite{Suite: tester.NewE2ESuite(
t,
[][]string{storeTD.AWSStorageCredEnvs, tconfig.M365AcctCredEnvs})})
}

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

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

suite.its = newIntegrationTesterSetup(t)
suite.dpnd = prepM365Test(t, ctx, path.SharePointService)
}

func (suite *BackupSharepointE2ESuite) TestSharepointBackupCmd_lists() {
runSharepointBackupCategoryTest(suite, flags.DataLists)
}

func runSharepointBackupCategoryTest(suite *BackupSharepointE2ESuite, category string) {
recorder := strings.Builder{}
recorder.Reset()

t := suite.T()

ctx, flush := tester.NewContext(t)
ctx = config.SetViper(ctx, suite.dpnd.vpr)

defer flush()

cmd, ctx := buildSharepointBackupCmd(
ctx,
suite.dpnd.configFilePath,
suite.its.site.ID,
category,
&recorder)

// run the command
err := cmd.ExecuteContext(ctx)
require.NoError(t, err, clues.ToCore(err))

result := recorder.String()
t.Log("backup results", result)
}

func (suite *BackupSharepointE2ESuite) TestSharepointBackupCmd_siteNotFound_lists() {
runSharepointBackupSiteNotFoundTest(suite, flags.DataLists)
}

func runSharepointBackupSiteNotFoundTest(suite *BackupSharepointE2ESuite, category string) {
recorder := strings.Builder{}
recorder.Reset()

t := suite.T()

ctx, flush := tester.NewContext(t)
ctx = config.SetViper(ctx, suite.dpnd.vpr)

defer flush()

cmd, ctx := buildSharepointBackupCmd(
ctx,
suite.dpnd.configFilePath,
uuid.NewString(),
category,
&recorder)

// run the command
err := cmd.ExecuteContext(ctx)
require.Error(t, err, clues.ToCore(err))
assert.Contains(
t,
err.Error(),
"Invalid hostname for this tenancy", "error missing site not found")
assert.NotContains(t, err.Error(), "runtime error", "panic happened")

t.Logf("backup error message: %s", err.Error())

result := recorder.String()
t.Log("backup results", result)
}

// ---------------------------------------------------------------------------
// tests prepared with a previous backup
// ---------------------------------------------------------------------------

type PreparedBackupSharepointE2ESuite struct {
tester.Suite
dpnd dependencies
backupOps map[path.CategoryType]string
its intgTesterSetup
}

func TestPreparedBackupSharepointE2ESuite(t *testing.T) {
suite.Run(t, &PreparedBackupSharepointE2ESuite{
Suite: tester.NewE2ESuite(
t,
[][]string{storeTD.AWSStorageCredEnvs, tconfig.M365AcctCredEnvs}),
})
}

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

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

suite.its = newIntegrationTesterSetup(t)
suite.dpnd = prepM365Test(t, ctx, path.SharePointService)
suite.backupOps = make(map[path.CategoryType]string)

var (
sites = []string{suite.its.site.ID}
ins = idname.NewCache(map[string]string{suite.its.site.ID: suite.its.site.ID})
cats = []path.CategoryType{
path.ListsCategory,
}
)

for _, set := range cats {
var (
sel = selectors.NewSharePointBackup(sites)
scopes []selectors.SharePointScope
)

switch set {
case path.ListsCategory:
scopes = selTD.SharePointBackupListsScope(sel)
}

sel.Include(scopes)

bop, err := suite.dpnd.repo.NewBackupWithLookup(ctx, sel.Selector, ins)
require.NoError(t, err, clues.ToCore(err))

err = bop.Run(ctx)
require.NoError(t, err, clues.ToCore(err))

bIDs := string(bop.Results.BackupID)

// sanity check, ensure we can find the backup and its details immediately
b, err := suite.dpnd.repo.Backup(ctx, string(bop.Results.BackupID))
require.NoError(t, err, "retrieving recent backup by ID")
require.Equal(t, bIDs, string(b.ID), "repo backup matches results id")

_, b, errs := suite.dpnd.repo.GetBackupDetails(ctx, bIDs)
require.NoError(t, errs.Failure(), "retrieving recent backup details by ID")
require.Empty(t, errs.Recovered(), "retrieving recent backup details by ID")
require.Equal(t, bIDs, string(b.ID), "repo details matches results id")

suite.backupOps[set] = string(b.ID)
}
}

func (suite *PreparedBackupSharepointE2ESuite) TestSharepointListCmd_lists() {
runSharepointListCmdTest(suite, path.ListsCategory)
}

func runSharepointListCmdTest(suite *PreparedBackupSharepointE2ESuite, category path.CategoryType) {
suite.dpnd.recorder.Reset()

t := suite.T()

ctx, flush := tester.NewContext(t)
ctx = config.SetViper(ctx, suite.dpnd.vpr)

defer flush()

cmd := cliTD.StubRootCmd(
"backup", "list", "sharepoint",
"--config-file", suite.dpnd.configFilePath)
cli.BuildCommandTree(cmd)
cmd.SetOut(&suite.dpnd.recorder)

ctx = print.SetRootCmd(ctx, cmd)

// run the command
err := cmd.ExecuteContext(ctx)
require.NoError(t, err, clues.ToCore(err))

// compare the output
result := suite.dpnd.recorder.String()
assert.Contains(t, result, suite.backupOps[category])

t.Log("backup results", result)
}

func (suite *PreparedBackupSharepointE2ESuite) TestSharepointListCmd_badID() {
t := suite.T()

ctx, flush := tester.NewContext(t)
ctx = config.SetViper(ctx, suite.dpnd.vpr)

defer flush()

cmd := cliTD.StubRootCmd(
"backup", "list", "sharepoint",
"--config-file", suite.dpnd.configFilePath,
"--backup", uuid.NewString())
cli.BuildCommandTree(cmd)

ctx = print.SetRootCmd(ctx, cmd)

// run the command
err := cmd.ExecuteContext(ctx)
require.Error(t, err, clues.ToCore(err))
}

func (suite *PreparedBackupSharepointE2ESuite) TestSharepointDetailsCmd_lists() {
runSharepointDetailsCmdTest(suite, path.ListsCategory)
}

func runSharepointDetailsCmdTest(suite *PreparedBackupSharepointE2ESuite, category path.CategoryType) {
suite.dpnd.recorder.Reset()

t := suite.T()

ctx, flush := tester.NewContext(t)
ctx = config.SetViper(ctx, suite.dpnd.vpr)

defer flush()

bID := suite.backupOps[category]

// fetch the details from the repo first
deets, _, errs := suite.dpnd.repo.GetBackupDetails(ctx, string(bID))
require.NoError(t, errs.Failure(), clues.ToCore(errs.Failure()))
require.Empty(t, errs.Recovered())

cmd := cliTD.StubRootCmd(
"backup", "details", "sharepoint",
"--config-file", suite.dpnd.configFilePath,
"--"+flags.BackupFN, string(bID))
cli.BuildCommandTree(cmd)
cmd.SetOut(&suite.dpnd.recorder)

ctx = print.SetRootCmd(ctx, cmd)

// run the command
err := cmd.ExecuteContext(ctx)
require.NoError(t, err, clues.ToCore(err))

// compare the output
result := suite.dpnd.recorder.String()

i := 0
foundList := 0

for _, ent := range deets.Entries {
if ent.SharePoint != nil && ent.SharePoint.ItemName != "" {
suite.Run(fmt.Sprintf("detail %d", i), func() {
assert.Contains(suite.T(), result, ent.ShortRef)
})
foundList++
i++
}
}

assert.GreaterOrEqual(t, foundList, 1)
}

// ---------------------------------------------------------------------------
// tests for deleting backups
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -114,7 +388,7 @@ func (suite *BackupDeleteSharePointE2ESuite) SetupSuite() {

// some tests require an existing backup
sel := selectors.NewSharePointBackup(sites)
sel.Include(testdata.SharePointBackupFolderScope(sel))
sel.Include(selTD.SharePointBackupFolderScope(sel))

backupOp, err := suite.dpnd.repo.NewBackupWithLookup(ctx, sel.Selector, ins)
require.NoError(t, err, clues.ToCore(err))
Expand Down Expand Up @@ -216,3 +490,23 @@ func (suite *BackupDeleteSharePointE2ESuite) TestSharePointBackupDeleteCmd_NoBac
err := cmd.ExecuteContext(ctx)
require.Error(t, err, clues.ToCore(err))
}

// ---------------------------------------------------------------------------
// helpers
// ---------------------------------------------------------------------------

func buildSharepointBackupCmd(
ctx context.Context,
configFile, site, category string,
recorder *strings.Builder,
) (*cobra.Command, context.Context) {
cmd := cliTD.StubRootCmd(
"backup", "create", "sharepoint",
"--config-file", configFile,
"--"+flags.SiteIDFN, site,
"--"+flags.CategoryDataFN, category)
cli.BuildCommandTree(cmd)
cmd.SetOut(recorder)

return cmd, print.SetRootCmd(ctx, cmd)
}
Loading
Loading