Consolidate/move OneDrive GraphConnector tests (#2487)

## Description

Now that we're also testing permissions behavior the OneDrive tests have gotten kind of large. This PR consolidates some of the code for tests and moves the OneDrive tests to their own file

It also sets things up so it's easier to add tests for different backup layouts in the future

Viewing by commit may make reviews easier

## 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

- [ ] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [x] 🤖 Test
- [ ] 💻 CI/Deployment
- [ ] 🧹 Tech Debt/Cleanup

## Issue(s)

* #2447

## Test Plan

<!-- How will this be tested prior to merging.-->
- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
ashmrtn 2023-02-14 13:27:25 -08:00 committed by GitHub
parent 570ce85656
commit 28fcafe3b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 821 additions and 1111 deletions

View File

@ -22,6 +22,7 @@ import (
"github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
@ -147,6 +148,16 @@ func testElementsMatch[T any](
) )
} }
type configInfo struct {
acct account.Account
opts control.Options
resource resource
service path.ServiceType
tenant string
resourceOwners []string
dest control.RestoreDestination
}
type itemInfo struct { type itemInfo struct {
// lookupKey is a string that can be used to find this data from a set of // lookupKey is a string that can be used to find this data from a set of
// other data in the same collection. This key should be something that will // other data in the same collection. This key should be something that will
@ -185,6 +196,8 @@ type restoreBackupInfoMultiVersion struct {
collectionsLatest []colInfo collectionsLatest []colInfo
collectionsPrevious []colInfo collectionsPrevious []colInfo
resource resource resource resource
backupVersion int
countMeta bool
} }
func attachmentEqual( func attachmentEqual(
@ -730,7 +743,6 @@ func compareOneDriveItem(
return return
} }
assert.Equal(t, len(expectedMeta.Permissions), len(itemMeta.Permissions), "number of permissions after restore")
testElementsMatch(t, expectedMeta.Permissions, itemMeta.Permissions, permissionEqual) testElementsMatch(t, expectedMeta.Permissions, itemMeta.Permissions, permissionEqual)
} }
@ -999,6 +1011,7 @@ func collectionsForInfo(
tenant, user string, tenant, user string,
dest control.RestoreDestination, dest control.RestoreDestination,
allInfo []colInfo, allInfo []colInfo,
backupVersion int,
) (int, int, []data.RestoreCollection, map[string]map[string][]byte) { ) (int, int, []data.RestoreCollection, map[string]map[string][]byte) {
collections := make([]data.RestoreCollection, 0, len(allInfo)) collections := make([]data.RestoreCollection, 0, len(allInfo))
expectedData := make(map[string]map[string][]byte, len(allInfo)) expectedData := make(map[string]map[string][]byte, len(allInfo))
@ -1031,7 +1044,7 @@ func collectionsForInfo(
baseExpected[info.items[i].lookupKey] = info.items[i].data baseExpected[info.items[i].lookupKey] = info.items[i].data
// We do not count metadata files against item count // We do not count metadata files against item count
if service != path.OneDriveService || if backupVersion == 0 || service != path.OneDriveService ||
(service == path.OneDriveService && (service == path.OneDriveService &&
strings.HasSuffix(info.items[i].name, onedrive.DataFileSuffix)) { strings.HasSuffix(info.items[i].name, onedrive.DataFileSuffix)) {
totalItems++ totalItems++
@ -1054,55 +1067,6 @@ func collectionsForInfo(
return totalItems, kopiaEntries, collections, expectedData return totalItems, kopiaEntries, collections, expectedData
} }
func collectionsForInfoVersion0(
t *testing.T,
service path.ServiceType,
tenant, user string,
dest control.RestoreDestination,
allInfo []colInfo,
) (int, int, []data.RestoreCollection, map[string]map[string][]byte) {
collections := make([]data.RestoreCollection, 0, len(allInfo))
expectedData := make(map[string]map[string][]byte, len(allInfo))
totalItems := 0
kopiaEntries := 0
for _, info := range allInfo {
pth := mustToDataLayerPath(
t,
service,
tenant,
user,
info.category,
info.pathElements,
false,
)
c := mockconnector.NewMockExchangeCollection(pth, pth, len(info.items))
baseDestPath := backupOutputPathFromRestore(t, dest, pth)
baseExpected := expectedData[baseDestPath.String()]
if baseExpected == nil {
expectedData[baseDestPath.String()] = make(map[string][]byte, len(info.items))
baseExpected = expectedData[baseDestPath.String()]
}
for i := 0; i < len(info.items); i++ {
c.Names[i] = info.items[i].name
c.Data[i] = info.items[i].data
baseExpected[info.items[i].lookupKey] = info.items[i].data
}
collections = append(collections, data.NotFoundRestoreCollection{
Collection: c,
})
totalItems += len(info.items)
kopiaEntries += len(info.items)
}
return totalItems, kopiaEntries, collections, expectedData
}
//nolint:deadcode
func getSelectorWith( func getSelectorWith(
t *testing.T, t *testing.T,
service path.ServiceType, service path.ServiceType,

View File

@ -0,0 +1,670 @@
package connector
import (
"encoding/base64"
"encoding/json"
"strings"
"testing"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/internal/connector/onedrive"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/path"
)
func getTestMetaJSON(t *testing.T, user string, roles []string) []byte {
id := base64.StdEncoding.EncodeToString([]byte(user + strings.Join(roles, "+")))
testMeta := onedrive.Metadata{Permissions: []onedrive.UserPermission{
{ID: id, Roles: roles, Email: user},
}}
testMetaJSON, err := json.Marshal(testMeta)
if err != nil {
t.Fatal("unable to marshall test permissions", err)
}
return testMetaJSON
}
func onedriveItemWithData(name string, itemData []byte) itemInfo {
return itemInfo{
name: name,
data: itemData,
lookupKey: name,
}
}
func onedriveFileWithMetadata(baseName string, fileData, metadata []byte) []itemInfo {
return []itemInfo{
onedriveItemWithData(baseName+onedrive.DataFileSuffix, fileData),
onedriveItemWithData(baseName+onedrive.MetaFileSuffix, metadata),
}
}
type GraphConnectorOneDriveIntegrationSuite struct {
suite.Suite
connector *GraphConnector
user string
secondaryUser string
acct account.Account
}
func TestGraphConnectorOneDriveIntegrationSuite(t *testing.T) {
tester.RunOnAny(
t,
tester.CorsoCITests,
tester.CorsoGraphConnectorTests,
tester.CorsoGraphConnectorExchangeTests)
suite.Run(t, new(GraphConnectorOneDriveIntegrationSuite))
}
func (suite *GraphConnectorOneDriveIntegrationSuite) SetupSuite() {
ctx, flush := tester.NewContext()
defer flush()
tester.MustGetEnvSets(suite.T(), tester.M365AcctCredEnvs)
suite.connector = loadConnector(ctx, suite.T(), graph.HTTPClient(graph.NoTimeout()), Users)
suite.user = tester.M365UserID(suite.T())
suite.secondaryUser = tester.SecondaryM365UserID(suite.T())
suite.acct = tester.NewM365Account(suite.T())
tester.LogTimeOfTest(suite.T())
}
var (
fileEmptyPerms = onedriveItemWithData(
"test-file.txt"+onedrive.MetaFileSuffix,
[]byte("{}"),
)
fileAEmptyPerms = []itemInfo{
onedriveItemWithData(
"test-file.txt"+onedrive.DataFileSuffix,
[]byte(strings.Repeat("a", 33)),
),
fileEmptyPerms,
}
fileBEmptyPerms = []itemInfo{
onedriveItemWithData(
"test-file.txt"+onedrive.DataFileSuffix,
[]byte(strings.Repeat("b", 65)),
),
fileEmptyPerms,
}
fileCEmptyPerms = []itemInfo{
onedriveItemWithData(
"test-file.txt"+onedrive.DataFileSuffix,
[]byte(strings.Repeat("c", 129)),
),
fileEmptyPerms,
}
fileDEmptyPerms = []itemInfo{
onedriveItemWithData(
"test-file.txt"+onedrive.DataFileSuffix,
[]byte(strings.Repeat("d", 257)),
),
fileEmptyPerms,
}
fileEEmptyPerms = []itemInfo{
onedriveItemWithData(
"test-file.txt"+onedrive.DataFileSuffix,
[]byte(strings.Repeat("e", 257)),
),
fileEmptyPerms,
}
folderAEmptyPerms = []itemInfo{
onedriveItemWithData("folder-a"+onedrive.DirMetaFileSuffix, []byte("{}")),
}
folderBEmptyPerms = []itemInfo{
onedriveItemWithData("b"+onedrive.DirMetaFileSuffix, []byte("{}")),
}
)
func withItems(items ...[]itemInfo) []itemInfo {
res := []itemInfo{}
for _, i := range items {
res = append(res, i...)
}
return res
}
func (suite *GraphConnectorOneDriveIntegrationSuite) TestRestoreAndBackup() {
ctx, flush := tester.NewContext()
defer flush()
// Get the default drive ID for the test user.
driveID := mustGetDefaultDriveID(
suite.T(),
ctx,
suite.connector.Service,
suite.user,
)
table := []restoreBackupInfo{
{
name: "OneDriveFoldersAndFilesWithMetadata",
service: path.OneDriveService,
resource: Users,
collections: []colInfo{
{
pathElements: []string{
"drives",
driveID,
"root:",
},
category: path.FilesCategory,
items: withItems(
onedriveFileWithMetadata(
"test-file.txt",
[]byte(strings.Repeat("a", 33)),
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}),
),
[]itemInfo{onedriveItemWithData(
"b"+onedrive.DirMetaFileSuffix,
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}),
)},
),
auxItems: []itemInfo{
onedriveItemWithData(
"test-file.txt"+onedrive.MetaFileSuffix,
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}),
),
},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"b",
},
category: path.FilesCategory,
items: onedriveFileWithMetadata(
"test-file.txt",
[]byte(strings.Repeat("e", 66)),
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}),
),
auxItems: []itemInfo{
onedriveItemWithData(
"test-file.txt"+onedrive.MetaFileSuffix,
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}),
),
},
},
},
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
runRestoreBackupTest(
t,
suite.acct,
test,
suite.connector.tenant,
[]string{suite.user},
control.Options{
RestorePermissions: true,
ToggleFeatures: control.Toggles{EnablePermissionsBackup: true},
},
)
})
}
}
func (suite *GraphConnectorOneDriveIntegrationSuite) TestRestoreAndBackup_Versions() {
ctx, flush := tester.NewContext()
defer flush()
// Get the default drive ID for the test user.
driveID := mustGetDefaultDriveID(
suite.T(),
ctx,
suite.connector.Service,
suite.user,
)
collectionsLatest := []colInfo{
{
pathElements: []string{
"drives",
driveID,
"root:",
},
category: path.FilesCategory,
items: withItems(
fileAEmptyPerms,
folderAEmptyPerms,
folderBEmptyPerms,
),
auxItems: []itemInfo{fileEmptyPerms},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"folder-a",
},
category: path.FilesCategory,
items: withItems(fileBEmptyPerms, folderBEmptyPerms),
auxItems: []itemInfo{fileEmptyPerms},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"folder-a",
"b",
},
category: path.FilesCategory,
items: withItems(fileCEmptyPerms, folderAEmptyPerms),
auxItems: []itemInfo{fileEmptyPerms},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"folder-a",
"b",
"folder-a",
},
category: path.FilesCategory,
items: fileDEmptyPerms,
auxItems: []itemInfo{fileEmptyPerms},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"b",
},
category: path.FilesCategory,
items: fileEEmptyPerms,
auxItems: []itemInfo{fileEmptyPerms},
},
}
table := []restoreBackupInfoMultiVersion{
{
name: "OneDriveMultipleFoldersAndFiles_Version0",
service: path.OneDriveService,
resource: Users,
backupVersion: 0, // The OG version ;)
countMeta: true,
collectionsPrevious: []colInfo{
{
pathElements: []string{
"drives",
driveID,
"root:",
},
category: path.FilesCategory,
items: []itemInfo{
onedriveItemWithData(
"test-file.txt",
[]byte(strings.Repeat("a", 33)),
),
},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"folder-a",
},
category: path.FilesCategory,
items: []itemInfo{
onedriveItemWithData(
"test-file.txt",
[]byte(strings.Repeat("b", 65)),
),
},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"folder-a",
"b",
},
category: path.FilesCategory,
items: []itemInfo{
onedriveItemWithData(
"test-file.txt",
[]byte(strings.Repeat("c", 129)),
),
},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"folder-a",
"b",
"folder-a",
},
category: path.FilesCategory,
items: []itemInfo{
onedriveItemWithData(
"test-file.txt",
[]byte(strings.Repeat("d", 257)),
),
},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"b",
},
category: path.FilesCategory,
items: []itemInfo{
onedriveItemWithData(
"test-file.txt",
[]byte(strings.Repeat("e", 257)),
),
},
},
},
collectionsLatest: collectionsLatest,
},
{
name: "OneDriveMultipleFoldersAndFiles_Version1",
service: path.OneDriveService,
resource: Users,
backupVersion: 1,
countMeta: false,
collectionsPrevious: collectionsLatest,
collectionsLatest: collectionsLatest,
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
runRestoreBackupTestVersions(
t,
suite.acct,
test,
suite.connector.tenant,
[]string{suite.user},
control.Options{
RestorePermissions: true,
ToggleFeatures: control.Toggles{EnablePermissionsBackup: true},
},
)
})
}
}
func (suite *GraphConnectorOneDriveIntegrationSuite) TestPermissionsRestoreAndBackup() {
ctx, flush := tester.NewContext()
defer flush()
// Get the default drive ID for the test user.
driveID := mustGetDefaultDriveID(
suite.T(),
ctx,
suite.connector.Service,
suite.user,
)
var (
fileAWritePerms = onedriveFileWithMetadata(
"test-file.txt",
[]byte(strings.Repeat("a", 33)),
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}),
)
fileEReadPerms = onedriveFileWithMetadata(
"test-file.txt",
[]byte(strings.Repeat("e", 66)),
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}),
)
folderBReadPerms = []itemInfo{onedriveItemWithData(
"b"+onedrive.DirMetaFileSuffix,
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}),
)}
fileWritePerms = onedriveItemWithData(
"test-file.txt"+onedrive.MetaFileSuffix,
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}),
)
fileReadPerms = onedriveItemWithData(
"test-file.txt"+onedrive.MetaFileSuffix,
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}),
)
)
table := []restoreBackupInfo{
{
name: "FilePermissionsRestore",
service: path.OneDriveService,
resource: Users,
collections: []colInfo{
{
pathElements: []string{
"drives",
driveID,
"root:",
},
category: path.FilesCategory,
items: fileAWritePerms,
auxItems: []itemInfo{fileWritePerms},
},
},
},
{
name: "FileInsideFolderPermissionsRestore",
service: path.OneDriveService,
resource: Users,
collections: []colInfo{
{
pathElements: []string{
"drives",
driveID,
"root:",
},
category: path.FilesCategory,
items: withItems(fileAEmptyPerms, folderBEmptyPerms),
auxItems: []itemInfo{fileEmptyPerms},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"b",
},
category: path.FilesCategory,
items: fileEReadPerms,
auxItems: []itemInfo{fileReadPerms},
},
},
},
{
name: "FileAndFolderPermissionsRestore",
service: path.OneDriveService,
resource: Users,
collections: []colInfo{
{
pathElements: []string{
"drives",
driveID,
"root:",
},
category: path.FilesCategory,
items: withItems(fileAWritePerms, folderBReadPerms),
auxItems: []itemInfo{fileWritePerms},
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"b",
},
category: path.FilesCategory,
items: fileEReadPerms,
auxItems: []itemInfo{fileReadPerms},
},
},
},
{
name: "FileAndFolderSeparatePermissionsRestore",
service: path.OneDriveService,
resource: Users,
collections: []colInfo{
{
pathElements: []string{
"drives",
driveID,
"root:",
},
category: path.FilesCategory,
items: folderBReadPerms,
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"b",
},
category: path.FilesCategory,
items: fileAWritePerms,
auxItems: []itemInfo{fileWritePerms},
},
},
},
{
name: "FolderAndNoChildPermissionsRestore",
service: path.OneDriveService,
resource: Users,
collections: []colInfo{
{
pathElements: []string{
"drives",
driveID,
"root:",
},
category: path.FilesCategory,
items: folderBReadPerms,
},
{
pathElements: []string{
"drives",
driveID,
"root:",
"b",
},
category: path.FilesCategory,
items: fileEEmptyPerms,
auxItems: []itemInfo{fileEmptyPerms},
},
},
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
runRestoreBackupTest(t,
suite.acct,
test,
suite.connector.tenant,
[]string{suite.user},
control.Options{
RestorePermissions: true,
ToggleFeatures: control.Toggles{EnablePermissionsBackup: true},
},
)
})
}
}
func (suite *GraphConnectorOneDriveIntegrationSuite) TestPermissionsBackupAndNoRestore() {
ctx, flush := tester.NewContext()
defer flush()
// Get the default drive ID for the test user.
driveID := mustGetDefaultDriveID(
suite.T(),
ctx,
suite.connector.Service,
suite.user,
)
table := []restoreBackupInfo{
{
name: "FilePermissionsRestore",
service: path.OneDriveService,
resource: Users,
collections: []colInfo{
{
pathElements: []string{
"drives",
driveID,
"root:",
},
category: path.FilesCategory,
items: onedriveFileWithMetadata(
"test-file.txt",
[]byte(strings.Repeat("a", 33)),
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}),
),
auxItems: []itemInfo{
onedriveItemWithData(
"test-file.txt"+onedrive.MetaFileSuffix,
getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}),
),
},
},
},
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
runRestoreBackupTest(
t,
suite.acct,
test,
suite.connector.tenant,
[]string{suite.user},
control.Options{
RestorePermissions: true,
ToggleFeatures: control.Toggles{EnablePermissionsBackup: true},
},
)
})
}
}

File diff suppressed because it is too large Load Diff