split op/backup tests into two files (#1968)
## Description A quick refactor to clean up the code and split op/backup testing between unit and integration test sets, so that we don't bloat a single file. No actual changes, just lift and shift. ## Does this PR need a docs update or release note? - [x] ⛔ No ## Type of change - [x] 🤖 Test ## Issue(s) * #1966 ## Test Plan - [x] 💚 E2E
This commit is contained in:
parent
b36ad340f2
commit
fe23d81c0a
430
src/internal/operations/backup_integration_test.go
Normal file
430
src/internal/operations/backup_integration_test.go
Normal file
@ -0,0 +1,430 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/connector/exchange"
|
||||
"github.com/alcionai/corso/src/internal/data"
|
||||
"github.com/alcionai/corso/src/internal/events"
|
||||
evmock "github.com/alcionai/corso/src/internal/events/mock"
|
||||
"github.com/alcionai/corso/src/internal/kopia"
|
||||
"github.com/alcionai/corso/src/internal/model"
|
||||
"github.com/alcionai/corso/src/internal/tester"
|
||||
"github.com/alcionai/corso/src/pkg/account"
|
||||
"github.com/alcionai/corso/src/pkg/backup"
|
||||
"github.com/alcionai/corso/src/pkg/control"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
"github.com/alcionai/corso/src/pkg/selectors"
|
||||
"github.com/alcionai/corso/src/pkg/store"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
//revive:disable:context-as-argument
|
||||
func prepNewBackupOp(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
bus events.Eventer,
|
||||
sel selectors.Selector,
|
||||
) (BackupOperation, account.Account, *kopia.Wrapper, *kopia.ModelStore, func()) {
|
||||
//revive:enable:context-as-argument
|
||||
acct := tester.NewM365Account(t)
|
||||
|
||||
// need to initialize the repository before we can test connecting to it.
|
||||
st := tester.NewPrefixedS3Storage(t)
|
||||
|
||||
k := kopia.NewConn(st)
|
||||
require.NoError(t, k.Initialize(ctx))
|
||||
|
||||
// kopiaRef comes with a count of 1 and Wrapper bumps it again so safe
|
||||
// to close here.
|
||||
closer := func() { k.Close(ctx) }
|
||||
|
||||
kw, err := kopia.NewWrapper(k)
|
||||
if !assert.NoError(t, err) {
|
||||
closer()
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
closer = func() {
|
||||
k.Close(ctx)
|
||||
kw.Close(ctx)
|
||||
}
|
||||
|
||||
ms, err := kopia.NewModelStore(k)
|
||||
if !assert.NoError(t, err) {
|
||||
closer()
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
closer = func() {
|
||||
k.Close(ctx)
|
||||
kw.Close(ctx)
|
||||
ms.Close(ctx)
|
||||
}
|
||||
|
||||
sw := store.NewKopiaStore(ms)
|
||||
|
||||
bo, err := NewBackupOperation(
|
||||
ctx,
|
||||
control.Options{},
|
||||
kw,
|
||||
sw,
|
||||
acct,
|
||||
sel,
|
||||
bus)
|
||||
if !assert.NoError(t, err) {
|
||||
closer()
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
return bo, acct, kw, ms, closer
|
||||
}
|
||||
|
||||
//revive:disable:context-as-argument
|
||||
func checkMetadataFilesExist(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
backupID model.StableID,
|
||||
kw *kopia.Wrapper,
|
||||
ms *kopia.ModelStore,
|
||||
tenant, user string,
|
||||
service path.ServiceType,
|
||||
category path.CategoryType,
|
||||
files []string,
|
||||
) {
|
||||
//revive:enable:context-as-argument
|
||||
bup := &backup.Backup{}
|
||||
|
||||
err := ms.Get(ctx, model.BackupSchema, backupID, bup)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
paths := []path.Path{}
|
||||
pathsByRef := map[string][]string{}
|
||||
|
||||
for _, fName := range files {
|
||||
p, err := path.Builder{}.
|
||||
Append(fName).
|
||||
ToServiceCategoryMetadataPath(tenant, user, service, category, true)
|
||||
if !assert.NoError(t, err, "bad metadata path") {
|
||||
continue
|
||||
}
|
||||
|
||||
dir, err := p.Dir()
|
||||
if !assert.NoError(t, err, "parent path") {
|
||||
continue
|
||||
}
|
||||
|
||||
paths = append(paths, p)
|
||||
pathsByRef[dir.ShortRef()] = append(pathsByRef[dir.ShortRef()], fName)
|
||||
}
|
||||
|
||||
cols, err := kw.RestoreMultipleItems(ctx, bup.SnapshotID, paths, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
for _, col := range cols {
|
||||
itemNames := []string{}
|
||||
|
||||
for item := range col.Items() {
|
||||
assert.Implements(t, (*data.StreamSize)(nil), item)
|
||||
|
||||
s := item.(data.StreamSize)
|
||||
assert.Greaterf(
|
||||
t,
|
||||
s.Size(),
|
||||
int64(0),
|
||||
"empty metadata file: %s/%s",
|
||||
col.FullPath(),
|
||||
item.UUID(),
|
||||
)
|
||||
|
||||
itemNames = append(itemNames, item.UUID())
|
||||
}
|
||||
|
||||
assert.ElementsMatchf(
|
||||
t,
|
||||
pathsByRef[col.FullPath().ShortRef()],
|
||||
itemNames,
|
||||
"collection %s missing expected files",
|
||||
col.FullPath(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// integration tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type BackupOpIntegrationSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func TestBackupOpIntegrationSuite(t *testing.T) {
|
||||
if err := tester.RunOnAny(
|
||||
tester.CorsoCITests,
|
||||
tester.CorsoOperationTests,
|
||||
tester.CorsoOperationBackupTests,
|
||||
); err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
|
||||
suite.Run(t, new(BackupOpIntegrationSuite))
|
||||
}
|
||||
|
||||
func (suite *BackupOpIntegrationSuite) SetupSuite() {
|
||||
_, err := tester.GetRequiredEnvSls(
|
||||
tester.AWSStorageCredEnvs,
|
||||
tester.M365AcctCredEnvs)
|
||||
require.NoError(suite.T(), err)
|
||||
}
|
||||
|
||||
func (suite *BackupOpIntegrationSuite) TestNewBackupOperation() {
|
||||
kw := &kopia.Wrapper{}
|
||||
sw := &store.Wrapper{}
|
||||
acct := tester.NewM365Account(suite.T())
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
opts control.Options
|
||||
kw *kopia.Wrapper
|
||||
sw *store.Wrapper
|
||||
acct account.Account
|
||||
targets []string
|
||||
errCheck assert.ErrorAssertionFunc
|
||||
}{
|
||||
{"good", control.Options{}, kw, sw, acct, nil, assert.NoError},
|
||||
{"missing kopia", control.Options{}, nil, sw, acct, nil, assert.Error},
|
||||
{"missing modelstore", control.Options{}, kw, nil, acct, nil, assert.Error},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
ctx, flush := tester.NewContext()
|
||||
defer flush()
|
||||
|
||||
_, err := NewBackupOperation(
|
||||
ctx,
|
||||
test.opts,
|
||||
test.kw,
|
||||
test.sw,
|
||||
test.acct,
|
||||
selectors.Selector{},
|
||||
evmock.NewBus())
|
||||
test.errCheck(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestBackup_Run ensures that Integration Testing works
|
||||
// for the following scopes: Contacts, Events, and Mail
|
||||
func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchange() {
|
||||
ctx, flush := tester.NewContext()
|
||||
defer flush()
|
||||
|
||||
m365UserID := tester.M365UserID(suite.T())
|
||||
users := []string{m365UserID}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
selectFunc func() *selectors.ExchangeBackup
|
||||
resourceOwner string
|
||||
category path.CategoryType
|
||||
metadataFiles []string
|
||||
}{
|
||||
{
|
||||
name: "Mail",
|
||||
selectFunc: func() *selectors.ExchangeBackup {
|
||||
sel := selectors.NewExchangeBackup(users)
|
||||
sel.Include(sel.MailFolders(users, []string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
|
||||
return sel
|
||||
},
|
||||
resourceOwner: m365UserID,
|
||||
category: path.EmailCategory,
|
||||
metadataFiles: exchange.MetadataFileNames(path.EmailCategory),
|
||||
},
|
||||
{
|
||||
name: "Contacts",
|
||||
selectFunc: func() *selectors.ExchangeBackup {
|
||||
sel := selectors.NewExchangeBackup(users)
|
||||
sel.Include(sel.ContactFolders(
|
||||
users,
|
||||
[]string{exchange.DefaultContactFolder},
|
||||
selectors.PrefixMatch()))
|
||||
|
||||
return sel
|
||||
},
|
||||
resourceOwner: m365UserID,
|
||||
category: path.ContactsCategory,
|
||||
metadataFiles: exchange.MetadataFileNames(path.ContactsCategory),
|
||||
},
|
||||
{
|
||||
name: "Calendar Events",
|
||||
selectFunc: func() *selectors.ExchangeBackup {
|
||||
sel := selectors.NewExchangeBackup(users)
|
||||
sel.Include(sel.EventCalendars(users, []string{exchange.DefaultCalendar}, selectors.PrefixMatch()))
|
||||
return sel
|
||||
},
|
||||
resourceOwner: m365UserID,
|
||||
category: path.EventsCategory,
|
||||
metadataFiles: exchange.MetadataFileNames(path.EventsCategory),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
mb := evmock.NewBus()
|
||||
sel := test.selectFunc()
|
||||
bo, acct, kw, ms, closer := prepNewBackupOp(t, ctx, mb, sel.Selector)
|
||||
defer closer()
|
||||
|
||||
failed := false
|
||||
|
||||
require.NoError(t, bo.Run(ctx))
|
||||
require.NotEmpty(t, bo.Results)
|
||||
require.NotEmpty(t, bo.Results.BackupID)
|
||||
|
||||
if !assert.Equalf(
|
||||
t,
|
||||
Completed,
|
||||
bo.Status,
|
||||
"backup status %s is not Completed",
|
||||
bo.Status,
|
||||
) {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if !assert.Less(t, 0, bo.Results.ItemsWritten) {
|
||||
failed = true
|
||||
}
|
||||
|
||||
assert.Less(t, 0, bo.Results.ItemsRead)
|
||||
assert.Less(t, int64(0), bo.Results.BytesRead, "bytes read")
|
||||
assert.Less(t, int64(0), bo.Results.BytesUploaded, "bytes uploaded")
|
||||
assert.Equal(t, 1, bo.Results.ResourceOwners)
|
||||
assert.NoError(t, bo.Results.ReadErrors)
|
||||
assert.NoError(t, bo.Results.WriteErrors)
|
||||
assert.Equal(t, 1, mb.TimesCalled[events.BackupStart], "backup-start events")
|
||||
assert.Equal(t, 1, mb.TimesCalled[events.BackupEnd], "backup-end events")
|
||||
assert.Equal(t,
|
||||
mb.CalledWith[events.BackupStart][0][events.BackupID],
|
||||
bo.Results.BackupID, "backupID pre-declaration")
|
||||
|
||||
// verify that we can find the new backup id in the manifests
|
||||
var (
|
||||
sck, scv = kopia.MakeServiceCat(sel.PathService(), test.category)
|
||||
oc = &kopia.OwnersCats{
|
||||
ResourceOwners: map[string]struct{}{test.resourceOwner: {}},
|
||||
ServiceCats: map[string]kopia.ServiceCat{sck: scv},
|
||||
}
|
||||
tags = map[string]string{kopia.TagBackupCategory: ""}
|
||||
found bool
|
||||
)
|
||||
|
||||
mans, err := kw.FetchPrevSnapshotManifests(ctx, oc, tags)
|
||||
assert.NoError(t, err)
|
||||
|
||||
for _, man := range mans {
|
||||
tk, _ := kopia.MakeTagKV(kopia.TagBackupID)
|
||||
if man.Tags[tk] == string(bo.Results.BackupID) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert.True(t, found, "backup retrieved by previous snapshot manifest")
|
||||
|
||||
if failed {
|
||||
return
|
||||
}
|
||||
|
||||
m365, err := acct.M365Config()
|
||||
require.NoError(t, err)
|
||||
|
||||
checkMetadataFilesExist(
|
||||
t,
|
||||
ctx,
|
||||
bo.Results.BackupID,
|
||||
kw,
|
||||
ms,
|
||||
m365.AzureTenantID,
|
||||
m365UserID,
|
||||
path.ExchangeService,
|
||||
test.category,
|
||||
test.metadataFiles,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackupOpIntegrationSuite) TestBackup_Run_oneDrive() {
|
||||
ctx, flush := tester.NewContext()
|
||||
defer flush()
|
||||
|
||||
var (
|
||||
t = suite.T()
|
||||
mb = evmock.NewBus()
|
||||
m365UserID = tester.SecondaryM365UserID(t)
|
||||
sel = selectors.NewOneDriveBackup([]string{m365UserID})
|
||||
)
|
||||
|
||||
sel.Include(sel.Users([]string{m365UserID}))
|
||||
|
||||
bo, _, _, _, closer := prepNewBackupOp(t, ctx, mb, sel.Selector)
|
||||
defer closer()
|
||||
|
||||
require.NoError(t, bo.Run(ctx))
|
||||
require.NotEmpty(t, bo.Results)
|
||||
require.NotEmpty(t, bo.Results.BackupID)
|
||||
assert.Equalf(t, Completed, bo.Status, "backup status %s is not Completed", bo.Status)
|
||||
assert.Equal(t, bo.Results.ItemsRead, bo.Results.ItemsWritten)
|
||||
assert.Less(t, int64(0), bo.Results.BytesRead, "bytes read")
|
||||
assert.Less(t, int64(0), bo.Results.BytesUploaded, "bytes uploaded")
|
||||
assert.Equal(t, 1, bo.Results.ResourceOwners)
|
||||
assert.NoError(t, bo.Results.ReadErrors)
|
||||
assert.NoError(t, bo.Results.WriteErrors)
|
||||
assert.Equal(t, 1, mb.TimesCalled[events.BackupStart], "backup-start events")
|
||||
assert.Equal(t, 1, mb.TimesCalled[events.BackupEnd], "backup-end events")
|
||||
assert.Equal(t,
|
||||
mb.CalledWith[events.BackupStart][0][events.BackupID],
|
||||
bo.Results.BackupID, "backupID pre-declaration")
|
||||
}
|
||||
|
||||
func (suite *BackupOpIntegrationSuite) TestBackup_Run_sharePoint() {
|
||||
ctx, flush := tester.NewContext()
|
||||
defer flush()
|
||||
|
||||
var (
|
||||
t = suite.T()
|
||||
mb = evmock.NewBus()
|
||||
siteID = tester.M365SiteID(t)
|
||||
sel = selectors.NewSharePointBackup([]string{siteID})
|
||||
)
|
||||
|
||||
sel.Include(sel.Sites([]string{siteID}))
|
||||
|
||||
bo, _, _, _, closer := prepNewBackupOp(t, ctx, mb, sel.Selector)
|
||||
defer closer()
|
||||
|
||||
require.NoError(t, bo.Run(ctx))
|
||||
require.NotEmpty(t, bo.Results)
|
||||
require.NotEmpty(t, bo.Results.BackupID)
|
||||
assert.Equalf(t, Completed, bo.Status, "backup status %s is not Completed", bo.Status)
|
||||
assert.Equal(t, bo.Results.ItemsRead, bo.Results.ItemsWritten)
|
||||
assert.Less(t, int64(0), bo.Results.BytesRead, "bytes read")
|
||||
assert.Less(t, int64(0), bo.Results.BytesUploaded, "bytes uploaded")
|
||||
assert.Equal(t, 1, bo.Results.ResourceOwners)
|
||||
assert.NoError(t, bo.Results.ReadErrors)
|
||||
assert.NoError(t, bo.Results.WriteErrors)
|
||||
assert.Equal(t, 1, mb.TimesCalled[events.BackupStart], "backup-start events")
|
||||
assert.Equal(t, 1, mb.TimesCalled[events.BackupEnd], "backup-end events")
|
||||
assert.Equal(t,
|
||||
mb.CalledWith[events.BackupStart][0][events.BackupID],
|
||||
bo.Results.BackupID, "backupID pre-declaration")
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user