Compare commits

...

7 Commits

Author SHA1 Message Date
Abhishek Pandey
8ff7f77267 Move conversion up in the func 2023-12-03 22:46:07 -08:00
Abhishek Pandey
cddb5b2d15 Fix unit test failures 2023-12-03 17:39:56 -08:00
Abhishek Pandey
1d971fb2ef Use custom drive items during backup 2023-12-03 17:34:02 -08:00
Abhishek Pandey
488c3458c9 Add some missing fields 2023-12-03 17:32:04 -08:00
Abhishek Pandey
efe8a9e1d2 Rename files, add nil item check 2023-12-01 22:33:49 -08:00
Abhishek Pandey
8025d4aa9a Add unit tests 2023-12-01 21:34:14 -08:00
Abhishek Pandey
c2f6a87e69 Add custom drive item 2023-12-01 02:07:07 -08:00
17 changed files with 865 additions and 54 deletions

View File

@ -10,7 +10,6 @@ import (
"time"
"github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/spatialcurrent/go-lazy/pkg/lazy"
"github.com/alcionai/corso/src/internal/common/idname"
@ -28,6 +27,7 @@ import (
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
const (
@ -52,7 +52,7 @@ type Collection struct {
// represents
folderPath path.Path
// M365 IDs of file items within this collection
driveItems map[string]models.DriveItemable
driveItems map[string]custom.LiteDriveItemable
// Primary M365 ID of the drive this collection was created from
driveID string
@ -172,7 +172,7 @@ func newColl(
protectedResource: resource,
folderPath: currPath,
prevPath: prevPath,
driveItems: map[string]models.DriveItemable{},
driveItems: map[string]custom.LiteDriveItemable{},
driveID: driveID,
data: dataCh,
statusUpdater: statusUpdater,
@ -190,7 +190,7 @@ func newColl(
// Adds an itemID to the collection. This will make it eligible to be
// populated. The return values denotes if the item was previously
// present or is new one.
func (oc *Collection) Add(item models.DriveItemable) bool {
func (oc *Collection) Add(item custom.LiteDriveItemable) bool {
_, found := oc.driveItems[ptr.Val(item.GetId())]
oc.driveItems[ptr.Val(item.GetId())] = item
@ -217,7 +217,7 @@ func (oc *Collection) IsEmpty() bool {
// ContainsItem returns true if the collection has the given item as one of its
// children.
func (oc Collection) ContainsItem(item models.DriveItemable) bool {
func (oc Collection) ContainsItem(item custom.LiteDriveItemable) bool {
_, ok := oc.driveItems[ptr.Val(item.GetId())]
return ok
}
@ -277,7 +277,7 @@ func (oc Collection) DoNotMergeItems() bool {
func (oc *Collection) getDriveItemContent(
ctx context.Context,
driveID string,
item models.DriveItemable,
item custom.LiteDriveItemable,
errs *fault.Bus,
) (io.ReadCloser, error) {
var (
@ -360,7 +360,7 @@ func downloadContent(
ctx context.Context,
iaag itemAndAPIGetter,
uc getItemPropertyer,
item models.DriveItemable,
item custom.LiteDriveItemable,
driveID string,
counter *count.Bus,
) (io.ReadCloser, error) {
@ -395,7 +395,9 @@ func downloadContent(
return nil, clues.Wrap(err, "retrieving expired item")
}
content, err = downloadItem(ctx, iaag, di)
ldi := custom.ToLiteDriveItemable(di)
content, err = downloadItem(ctx, iaag, ldi)
if err != nil {
return nil, clues.Wrap(err, "content download retry")
}
@ -489,7 +491,7 @@ func (oc *Collection) streamItems(ctx context.Context, errs *fault.Bus) {
wg.Add(1)
go func(item models.DriveItemable) {
go func(item custom.LiteDriveItemable) {
defer wg.Done()
defer func() { <-semaphoreCh }()
@ -513,14 +515,14 @@ func (oc *Collection) streamItems(ctx context.Context, errs *fault.Bus) {
type lazyItemGetter struct {
info *details.ItemInfo
item models.DriveItemable
item custom.LiteDriveItemable
driveID string
suffix string
itemExtensionFactory []extensions.CreateItemExtensioner
contentGetter func(
ctx context.Context,
driveID string,
item models.DriveItemable,
item custom.LiteDriveItemable,
errs *fault.Bus) (io.ReadCloser, error)
}
@ -561,7 +563,7 @@ func (lig *lazyItemGetter) GetData(
func (oc *Collection) streamDriveItem(
ctx context.Context,
parentPath *path.Builder,
item models.DriveItemable,
item custom.LiteDriveItemable,
stats *driveStats,
itemExtensionFactory []extensions.CreateItemExtensioner,
errs *fault.Bus,
@ -584,7 +586,7 @@ func (oc *Collection) streamDriveItem(
"item_name", clues.Hide(itemName),
"item_size", itemSize)
item.SetParentReference(setName(item.GetParentReference(), oc.driveName))
item.SetParentReference(custom.SetParentName(item.GetParentReference(), oc.driveName))
isFile := item.GetFile() != nil

View File

@ -34,6 +34,7 @@ import (
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
// ---------------------------------------------------------------------------
@ -232,7 +233,7 @@ func (suite *CollectionUnitSuite) TestCollection() {
true)
for i := 0; i < test.numInstances; i++ {
coll.Add(stubItem)
coll.Add(custom.ToLiteDriveItemable(stubItem))
}
// Read items from the collection
@ -352,7 +353,7 @@ func (suite *CollectionUnitSuite) TestCollectionReadError() {
true,
false)
coll.Add(stubItem)
coll.Add(custom.ToLiteDriveItemable(stubItem))
collItem, ok := <-coll.Items(ctx, fault.New(true))
assert.True(t, ok)
@ -422,7 +423,7 @@ func (suite *CollectionUnitSuite) TestCollectionReadUnauthorizedErrorRetry() {
count.New())
require.NoError(t, err, clues.ToCore(err))
coll.Add(stubItem)
coll.Add(custom.ToLiteDriveItemable(stubItem))
collItem, ok := <-coll.Items(ctx, fault.New(true))
assert.True(t, ok)
@ -490,7 +491,7 @@ func (suite *CollectionUnitSuite) TestCollectionPermissionBackupLatestModTime()
true,
false)
coll.Add(stubItem)
coll.Add(custom.ToLiteDriveItemable(stubItem))
coll.handler = mbh
@ -641,7 +642,7 @@ func (suite *GetDriveItemUnitTestSuite) TestGetDriveItem_error() {
col.handler = mbh
_, err := col.getDriveItemContent(ctx, "driveID", stubItem, errs)
_, err := col.getDriveItemContent(ctx, "driveID", custom.ToLiteDriveItemable(stubItem), errs)
if test.err == nil {
assert.NoError(t, err, clues.ToCore(err))
return
@ -819,7 +820,7 @@ func (suite *GetDriveItemUnitTestSuite) TestDownloadContent() {
mbh.GetResps = resps
mbh.GetErrs = test.getErr
r, err := downloadContent(ctx, mbh, test.muc, item, driveID, count.New())
r, err := downloadContent(ctx, mbh, test.muc, custom.ToLiteDriveItemable(item), driveID, count.New())
test.expect(t, r)
test.expectErr(t, err, clues.ToCore(err))
})
@ -1020,7 +1021,7 @@ func (suite *CollectionUnitSuite) TestItemExtensions() {
true,
false)
coll.Add(stubItem)
coll.Add(custom.ToLiteDriveItemable(stubItem))
collItem, ok := <-coll.Items(ctx, fault.New(true))
assert.True(t, ok)

View File

@ -27,6 +27,7 @@ import (
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
"github.com/alcionai/corso/src/pkg/services/m365/api/pagers"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
const (
@ -715,7 +716,7 @@ func (c *Collections) handleDelete(
func (c *Collections) getCollectionPath(
driveID string,
item models.DriveItemable,
item custom.LiteDriveItemable,
) (path.Path, error) {
var (
pb = odConsts.DriveFolderPrefixBuilder(driveID)
@ -930,7 +931,7 @@ func (c *Collections) PopulateDriveCollections(
func (c *Collections) processItem(
ctx context.Context,
item models.DriveItemable,
di models.DriveItemable,
driveID, driveName string,
oldPrevPaths, currPrevPaths, newPrevPaths map[string]string,
seenFolders map[string]string,
@ -943,6 +944,7 @@ func (c *Collections) processItem(
skipper fault.AddSkipper,
) error {
var (
item = custom.ToLiteDriveItemable(di)
itemID = ptr.Val(item.GetId())
itemName = ptr.Val(item.GetName())
isFolder = item.GetFolder() != nil || item.GetPackageEscaped() != nil

View File

@ -18,6 +18,7 @@ import (
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
"github.com/alcionai/corso/src/pkg/services/m365/api/pagers"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
// ---------------------------------------------------------------------------
@ -464,7 +465,7 @@ func (c *Collections) addFolderToTree(
driveID,
folderID,
folderName,
graph.ItemInfo(folder))
graph.ItemInfo(custom.ToLiteDriveItemable(folder)))
logger.Ctx(ctx).Infow("malware detected")

View File

@ -2,7 +2,6 @@ package drive
import (
"github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/alcionai/corso/src/internal/common/idname"
"github.com/alcionai/corso/src/internal/common/ptr"
@ -11,6 +10,7 @@ import (
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
var _ BackupHandler = &groupBackupHandler{}
@ -105,7 +105,7 @@ func (h groupBackupHandler) SitePathPrefix(tenantID string) (path.Path, error) {
func (h groupBackupHandler) AugmentItemInfo(
dii details.ItemInfo,
resource idname.Provider,
item models.DriveItemable,
item custom.LiteDriveItemable,
size int64,
parentPath *path.Builder,
) details.ItemInfo {

View File

@ -3,12 +3,11 @@ package drive
import (
"strings"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/alcionai/corso/src/internal/common/ptr"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
func getItemCreator(item models.DriveItemable) string {
func getItemCreator(item custom.LiteDriveItemable) string {
if item.GetCreatedBy() == nil || item.GetCreatedBy().GetUser() == nil {
return ""
}
@ -30,7 +29,7 @@ func getItemCreator(item models.DriveItemable) string {
return *ed.(*string)
}
func getItemDriveInfo(item models.DriveItemable) (string, string) {
func getItemDriveInfo(item custom.LiteDriveItemable) (string, string) {
if item.GetParentReference() == nil {
return "", ""
}

View File

@ -12,6 +12,7 @@ import (
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/pagers"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
type ItemInfoAugmenter interface {
@ -23,7 +24,7 @@ type ItemInfoAugmenter interface {
AugmentItemInfo(
dii details.ItemInfo,
resource idname.Provider,
item models.DriveItemable,
item custom.LiteDriveItemable,
size int64,
parentPath *path.Builder,
) details.ItemInfo

View File

@ -7,7 +7,6 @@ import (
"io"
"github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"golang.org/x/exp/maps"
"github.com/alcionai/corso/src/internal/common/ptr"
@ -18,6 +17,7 @@ import (
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
const (
@ -34,7 +34,7 @@ var downloadURLKeys = []string{
func downloadItem(
ctx context.Context,
ag api.Getter,
item models.DriveItemable,
item custom.LiteDriveItemable,
) (io.ReadCloser, error) {
if item == nil {
return nil, clues.New("nil item")
@ -152,7 +152,7 @@ func downloadItemMeta(
ctx context.Context,
getter GetItemPermissioner,
driveID string,
item models.DriveItemable,
item custom.LiteDriveItemable,
) (io.ReadCloser, int, error) {
meta := metadata.Metadata{
FileName: ptr.Val(item.GetName()),
@ -204,13 +204,3 @@ func driveItemWriter(
return iw, ptr.Val(icu.GetUploadUrl()), nil
}
func setName(orig models.ItemReferenceable, driveName string) models.ItemReferenceable {
if orig == nil {
return nil
}
orig.SetName(&driveName)
return orig
}

View File

@ -25,6 +25,7 @@ import (
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
type ItemIntegrationSuite struct {
@ -123,7 +124,7 @@ func (suite *ItemIntegrationSuite) TestItemReader_oneDrive() {
}
// Read data for the file
itemData, err := downloadItem(ctx, bh, driveItem)
itemData, err := downloadItem(ctx, bh, custom.ToLiteDriveItemable(driveItem))
require.NoError(t, err, clues.ToCore(err))
size, err := io.Copy(io.Discard, itemData)
@ -462,7 +463,7 @@ func (suite *ItemUnitTestSuite) TestDownloadItem() {
mg := mockGetter{
GetFunc: test.GetFunc,
}
rc, err := downloadItem(ctx, mg, test.itemFunc())
rc, err := downloadItem(ctx, mg, custom.ToLiteDriveItemable(test.itemFunc()))
test.errorExpected(t, err, clues.ToCore(err))
test.rcExpected(t, rc)
})
@ -521,7 +522,7 @@ func (suite *ItemUnitTestSuite) TestDownloadItem_ConnectionResetErrorOnFirstRead
mg := mockGetter{
GetFunc: GetFunc,
}
rc, err := downloadItem(ctx, mg, itemFunc())
rc, err := downloadItem(ctx, mg, custom.ToLiteDriveItemable(itemFunc()))
errorExpected(t, err, clues.ToCore(err))
rcExpected(t, rc)

View File

@ -30,6 +30,7 @@ import (
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/graph"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
const (
@ -863,7 +864,7 @@ func restoreFile(
dii := ir.AugmentItemInfo(
details.ItemInfo{},
rcc.ProtectedResource,
newItem,
custom.ToLiteDriveItemable(newItem),
written,
nil)

View File

@ -17,6 +17,7 @@ import (
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/pagers"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
type baseSiteHandler struct {
@ -33,7 +34,7 @@ func (h baseSiteHandler) NewDrivePager(
func (h baseSiteHandler) AugmentItemInfo(
dii details.ItemInfo,
resource idname.Provider,
item models.DriveItemable,
item custom.LiteDriveItemable,
size int64,
parentPath *path.Builder,
) details.ItemInfo {

View File

@ -17,6 +17,7 @@ import (
"github.com/alcionai/corso/src/pkg/selectors"
"github.com/alcionai/corso/src/pkg/services/m365/api"
"github.com/alcionai/corso/src/pkg/services/m365/api/pagers"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
// ---------------------------------------------------------------------------
@ -42,7 +43,7 @@ func (h baseUserDriveHandler) NewDrivePager(
func (h baseUserDriveHandler) AugmentItemInfo(
dii details.ItemInfo,
resource idname.Provider,
item models.DriveItemable,
item custom.LiteDriveItemable,
size int64,
parentPath *path.Builder,
) details.ItemInfo {

View File

@ -17,6 +17,7 @@ import (
"github.com/alcionai/corso/src/pkg/services/m365/api"
apiMock "github.com/alcionai/corso/src/pkg/services/m365/api/mock"
"github.com/alcionai/corso/src/pkg/services/m365/api/pagers"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
// ---------------------------------------------------------------------------
@ -165,7 +166,7 @@ func (h BackupHandler[T]) NewLocationIDer(driveID string, elems ...string) detai
func (h BackupHandler[T]) AugmentItemInfo(
details.ItemInfo,
idname.Provider,
models.DriveItemable,
custom.LiteDriveItemable,
int64,
*path.Builder,
) details.ItemInfo {
@ -405,7 +406,7 @@ func (h RestoreHandler) NewDrivePager(string, []string) pagers.NonDeltaHandler[m
func (h *RestoreHandler) AugmentItemInfo(
details.ItemInfo,
idname.Provider,
models.DriveItemable,
custom.LiteDriveItemable,
int64,
*path.Builder,
) details.ItemInfo {

View File

@ -10,7 +10,6 @@ import (
"syscall"
"github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors"
"github.com/pkg/errors"
@ -20,6 +19,7 @@ import (
"github.com/alcionai/corso/src/internal/common/str"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/filters"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
// ---------------------------------------------------------------------------
@ -510,7 +510,7 @@ func appendIf(a []any, k string, v *string) []any {
// ItemInfo gathers potentially useful information about a drive item,
// and aggregates that data into a map.
func ItemInfo(item models.DriveItemable) map[string]any {
func ItemInfo(item custom.LiteDriveItemable) map[string]any {
m := map[string]any{}
creator := item.GetCreatedByUser()

View File

@ -17,6 +17,7 @@ import (
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/fault"
graphTD "github.com/alcionai/corso/src/pkg/services/m365/api/graph/testdata"
"github.com/alcionai/corso/src/pkg/services/m365/custom"
)
type GraphErrorsUnitSuite struct {
@ -532,7 +533,7 @@ func (suite *GraphErrorsUnitSuite) TestMalwareInfo() {
fault.AddtlMalwareDesc: malDesc,
}
assert.Equal(suite.T(), expect, ItemInfo(i))
assert.Equal(suite.T(), expect, ItemInfo(custom.ToLiteDriveItemable(i)))
}
func (suite *GraphErrorsUnitSuite) TestIsErrFolderExists() {

View File

@ -0,0 +1,350 @@
// Disable revive linter since any structs in this file will expose the same
// funcs as the original structs in the msgraph-sdk-go package, which do not
// follow some of the golint rules.
//
//nolint:revive
package custom
import (
"strings"
"time"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/alcionai/corso/src/internal/common/ptr"
"github.com/alcionai/corso/src/internal/common/str"
)
// Replica of models.DriveItemable
type LiteDriveItemable interface {
GetId() *string
GetName() *string
GetSize() *int64
GetFolder() interface{}
GetPackageEscaped() interface{}
GetShared() interface{}
GetMalware() malwareable
GetDeleted() interface{}
GetRoot() interface{}
GetFile() fileItemable
GetParentReference() itemReferenceable
SetParentReference(itemReferenceable)
GetCreatedBy() identitySetable
GetCreatedByUser() userable
GetLastModifiedByUser() userable
GetCreatedDateTime() *time.Time
GetLastModifiedDateTime() *time.Time
GetAdditionalData() map[string]interface{}
}
var _ LiteDriveItemable = &driveItem{}
type driveItem struct {
id string
name string
size int64
folder interface{}
pkg interface{}
shared interface{}
deleted interface{}
root interface{}
malware malwareable
file fileItemable
parentRef itemReferenceable
createdBy identitySetable
createdByUser userable
lastModifiedByUser userable
createdDateTime time.Time
lastModifiedDateTime time.Time
additionalData map[string]interface{}
}
func (c *driveItem) GetId() *string {
return &c.id
}
func (c *driveItem) GetName() *string {
return &c.name
}
func (c *driveItem) GetSize() *int64 {
return &c.size
}
func (c *driveItem) GetFolder() interface{} {
return c.folder
}
func (c *driveItem) GetPackageEscaped() interface{} {
return c.pkg
}
func (c *driveItem) GetShared() interface{} {
return c.shared
}
func (c *driveItem) GetMalware() malwareable {
return c.malware
}
func (c *driveItem) GetDeleted() interface{} {
return c.deleted
}
func (c *driveItem) GetRoot() interface{} {
return c.root
}
func (c *driveItem) GetFile() fileItemable {
return c.file
}
func (c *driveItem) GetParentReference() itemReferenceable {
return c.parentRef
}
// TODO(pandeyabs): Should we only support GETs?
func (c *driveItem) SetParentReference(parent itemReferenceable) {
c.parentRef = parent
}
func (c *driveItem) GetCreatedBy() identitySetable {
return c.createdBy
}
func (c *driveItem) GetCreatedByUser() userable {
return c.createdByUser
}
func (c *driveItem) GetLastModifiedByUser() userable {
return c.lastModifiedByUser
}
func (c *driveItem) GetCreatedDateTime() *time.Time {
return &c.createdDateTime
}
func (c *driveItem) GetLastModifiedDateTime() *time.Time {
return &c.lastModifiedDateTime
}
func (c *driveItem) GetAdditionalData() map[string]interface{} {
return c.additionalData
}
type (
malwareable interface {
GetDescription() *string
}
fileItemable interface {
GetMimeType() *string
}
itemReferenceable interface {
GetPath() *string
GetId() *string
GetName() *string
GetDriveId() *string
}
identitySetable interface {
GetUser() identityable
}
identityable interface {
GetAdditionalData() map[string]interface{}
}
userable interface {
GetId() *string
}
)
// Concrete implementations
var _ malwareable = &malware{}
type malware struct {
description string
}
func (m *malware) GetDescription() *string {
return &m.description
}
var _ fileItemable = &fileItem{}
type fileItem struct {
mimeType string
}
func (f *fileItem) GetMimeType() *string {
return &f.mimeType
}
var _ itemReferenceable = &parentRef{}
type parentRef struct {
path string
id string
name string
driveID string
}
func (pr *parentRef) GetPath() *string {
return &pr.path
}
func (pr *parentRef) GetId() *string {
return &pr.id
}
func (pr *parentRef) GetName() *string {
return &pr.name
}
func (pr *parentRef) GetDriveId() *string {
return &pr.driveID
}
var _ identitySetable = &identitySet{}
type identitySet struct {
identity identityable
}
func (iis *identitySet) GetUser() identityable {
return iis.identity
}
var _ identityable = &identity{}
type identity struct {
additionalData map[string]interface{}
}
func (iu *identity) GetAdditionalData() map[string]interface{} {
return iu.additionalData
}
var _ userable = &user{}
type user struct {
id string
}
func (u *user) GetId() *string {
return &u.id
}
// TODO(pandeyabs): This is duplicated from collection/drive package.
// Move to common pkg
var downloadURLKeys = []string{
"@microsoft.graph.downloadUrl",
"@content.downloadUrl",
}
func ToLiteDriveItemable(item models.DriveItemable) LiteDriveItemable {
if item == nil {
return nil
}
di := &driveItem{
id: strings.Clone(ptr.Val(item.GetId())),
name: strings.Clone(ptr.Val(item.GetName())),
size: ptr.Val(item.GetSize()),
createdDateTime: ptr.Val(item.GetCreatedDateTime()),
lastModifiedDateTime: ptr.Val(item.GetLastModifiedDateTime()),
}
if item.GetFolder() != nil {
di.folder = &struct{}{}
} else if item.GetFile() != nil {
di.file = &fileItem{
mimeType: strings.Clone(ptr.Val(item.GetFile().GetMimeType())),
}
} else if item.GetPackageEscaped() != nil {
di.pkg = &struct{}{}
}
if item.GetParentReference() != nil {
di.parentRef = &parentRef{
id: strings.Clone(ptr.Val(item.GetParentReference().GetId())),
path: strings.Clone(ptr.Val(item.GetParentReference().GetPath())),
name: strings.Clone(ptr.Val(item.GetParentReference().GetName())),
driveID: strings.Clone(ptr.Val(item.GetParentReference().GetDriveId())),
}
}
if item.GetShared() != nil {
di.shared = &struct{}{}
}
if item.GetMalware() != nil {
di.malware = &malware{
description: strings.Clone(ptr.Val(item.GetMalware().GetDescription())),
}
}
if item.GetDeleted() != nil {
di.deleted = &struct{}{}
}
if item.GetRoot() != nil {
di.root = &struct{}{}
}
if item.GetCreatedBy() != nil && item.GetCreatedBy().GetUser() != nil {
additionalData := item.GetCreatedBy().GetUser().GetAdditionalData()
ad := make(map[string]interface{})
if v, err := str.AnyValueToString("email", additionalData); err == nil {
email := strings.Clone(v)
ad["email"] = &email
}
if v, err := str.AnyValueToString("displayName", additionalData); err == nil {
displayName := strings.Clone(v)
ad["displayName"] = &displayName
}
di.createdBy = &identitySet{
identity: &identity{
additionalData: ad,
},
}
}
if item.GetCreatedByUser() != nil {
di.createdByUser = &user{
id: strings.Clone(ptr.Val(item.GetCreatedByUser().GetId())),
}
}
if item.GetLastModifiedByUser() != nil {
di.lastModifiedByUser = &user{
id: strings.Clone(ptr.Val(item.GetLastModifiedByUser().GetId())),
}
}
// We only use the download URL from additional data
ad := make(map[string]interface{})
for _, key := range downloadURLKeys {
if v, err := str.AnyValueToString(key, item.GetAdditionalData()); err == nil {
downloadURL := strings.Clone(v)
ad[key] = &downloadURL
}
}
di.additionalData = ad
return di
}
func SetParentName(orig itemReferenceable, driveName string) itemReferenceable {
if orig == nil {
return nil
}
pr := orig.(*parentRef)
pr.name = driveName
return pr
}

View File

@ -0,0 +1,459 @@
// funcs as the original structs in the msgraph-sdk-go package, which do not
// follow some of the golint rules.
//
//nolint:revive
package custom
import (
"testing"
"time"
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"gotest.tools/v3/assert"
"github.com/alcionai/corso/src/internal/common/ptr"
"github.com/alcionai/corso/src/internal/common/str"
"github.com/alcionai/corso/src/internal/tester"
)
type driveUnitSuite struct {
tester.Suite
}
func TestDriveUnitSuite(t *testing.T) {
suite.Run(t, &driveUnitSuite{
Suite: tester.NewUnitSuite(t),
})
}
func (suite *driveUnitSuite) TestToLiteDriveItemable() {
id := "itemID"
table := []struct {
name string
itemFunc func() models.DriveItemable
validateFunc func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable)
}{
{
name: "nil item",
itemFunc: func() models.DriveItemable {
return nil
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.Nil(t, got)
},
},
{
name: "uninitialized values",
itemFunc: func() models.DriveItemable {
di := models.NewDriveItem()
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
assert.Equal(t, ptr.Val(got.GetId()), "")
assert.Equal(t, ptr.Val(got.GetName()), "")
assert.Equal(t, ptr.Val(got.GetSize()), int64(0))
assert.Equal(t, ptr.Val(got.GetCreatedDateTime()), time.Time{})
assert.Equal(t, ptr.Val(got.GetLastModifiedDateTime()), time.Time{})
require.Nil(t, got.GetFolder())
require.Nil(t, got.GetFile())
require.Nil(t, got.GetPackageEscaped())
require.Nil(t, got.GetShared())
require.Nil(t, got.GetMalware())
require.Nil(t, got.GetDeleted())
require.Nil(t, got.GetRoot())
require.Nil(t, got.GetCreatedBy())
require.Nil(t, got.GetCreatedByUser())
require.Nil(t, got.GetLastModifiedByUser())
require.Nil(t, got.GetParentReference())
assert.Equal(t, len(got.GetAdditionalData()), 0)
},
},
{
name: "ID, name, size, created, modified",
itemFunc: func() models.DriveItemable {
name := "itemName"
size := int64(6)
created := time.Now().Add(-time.Second)
modified := time.Now()
di := models.NewDriveItem()
di.SetId(&id)
di.SetName(&name)
di.SetSize(&size)
di.SetCreatedDateTime(&created)
di.SetLastModifiedDateTime(&modified)
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
assert.Equal(t, ptr.Val(got.GetId()), ptr.Val(expected.GetId()))
assert.Equal(t, ptr.Val(got.GetName()), ptr.Val(expected.GetName()))
assert.Equal(t, ptr.Val(got.GetSize()), ptr.Val(expected.GetSize()))
require.True(
t,
got.GetCreatedDateTime().Equal(ptr.Val(expected.GetCreatedDateTime())))
require.True(
t,
got.GetLastModifiedDateTime().Equal(ptr.Val(expected.GetLastModifiedDateTime())))
},
},
{
name: "Folder item",
itemFunc: func() models.DriveItemable {
di := models.NewDriveItem()
di.SetId(&id)
di.SetFolder(models.NewFolder())
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetFolder())
require.Nil(t, got.GetFile())
require.Nil(t, got.GetPackageEscaped())
assert.Equal(t, ptr.Val(got.GetId()), ptr.Val(expected.GetId()))
},
},
{
name: "Package item",
itemFunc: func() models.DriveItemable {
di := models.NewDriveItem()
di.SetId(&id)
di.SetPackageEscaped(models.NewPackageEscaped())
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetPackageEscaped())
require.Nil(t, got.GetFile())
require.Nil(t, got.GetFolder())
assert.Equal(t, ptr.Val(got.GetId()), ptr.Val(expected.GetId()))
},
},
{
name: "File item",
itemFunc: func() models.DriveItemable {
mime := "mimeType"
di := models.NewDriveItem()
di.SetId(&id)
di.SetFile(models.NewFile())
di.GetFile().SetMimeType(&mime)
// Intentionally set different URLs for the two keys to test
// for correctness. It's unlikely that a) both will be set,
// b) URLs will be different, but it's not the responsibility
// of function being tested, which is simply copying over key, val
// pairs useful to callers.
di.SetAdditionalData(map[string]interface{}{
"@microsoft.graph.downloadUrl": "downloadURL",
"@content.downloadUrl": "contentURL",
})
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetFile())
require.Nil(t, got.GetFolder())
require.Nil(t, got.GetPackageEscaped())
assert.Equal(t, ptr.Val(got.GetId()), ptr.Val(expected.GetId()))
assert.Equal(
t,
ptr.Val(got.GetFile().GetMimeType()),
ptr.Val(expected.GetFile().GetMimeType()))
// additional data
urlExpected, err := str.AnyValueToString(
"@microsoft.graph.downloadUrl",
expected.GetAdditionalData())
require.NoError(t, err)
urlGot, err := str.AnyValueToString(
"@microsoft.graph.downloadUrl",
got.GetAdditionalData())
require.NoError(t, err)
assert.Equal(
t,
urlGot,
urlExpected)
contentExpected, err := str.AnyValueToString(
"@content.downloadUrl",
expected.GetAdditionalData())
require.NoError(t, err)
contentGot, err := str.AnyValueToString(
"@content.downloadUrl",
got.GetAdditionalData())
require.NoError(t, err)
assert.Equal(
t,
contentGot,
contentExpected)
},
},
{
name: "Shared item",
itemFunc: func() models.DriveItemable {
di := models.NewDriveItem()
di.SetId(&id)
di.SetShared(models.NewShared())
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetShared())
assert.Equal(t, ptr.Val(got.GetId()), ptr.Val(expected.GetId()))
},
},
{
name: "Malware item",
itemFunc: func() models.DriveItemable {
di := models.NewDriveItem()
mw := models.NewMalware()
desc := "malware description"
mw.SetDescription(&desc)
di.SetId(&id)
di.SetMalware(mw)
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetMalware())
assert.Equal(
t,
ptr.Val(expected.GetMalware().GetDescription()),
ptr.Val(got.GetMalware().GetDescription()))
assert.Equal(t, ptr.Val(got.GetId()), ptr.Val(expected.GetId()))
},
},
{
name: "Deleted item",
itemFunc: func() models.DriveItemable {
di := models.NewDriveItem()
di.SetId(&id)
di.SetDeleted(models.NewDeleted())
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetDeleted())
assert.Equal(t, ptr.Val(got.GetId()), ptr.Val(expected.GetId()))
},
},
{
name: "Root item",
itemFunc: func() models.DriveItemable {
di := models.NewDriveItem()
di.SetId(&id)
di.SetRoot(models.NewRoot())
di.SetFolder(models.NewFolder())
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetRoot())
require.NotNil(t, got.GetFolder())
assert.Equal(t, ptr.Val(got.GetId()), ptr.Val(expected.GetId()))
},
},
{
name: "Parent reference",
itemFunc: func() models.DriveItemable {
parentID := "parentID"
parentPath := "/parentPath"
parentName := "parentName"
parentDriveID := "parentDriveID"
parentRef := models.NewItemReference()
parentRef.SetId(&parentID)
parentRef.SetPath(&parentPath)
parentRef.SetName(&parentName)
parentRef.SetDriveId(&parentDriveID)
di := models.NewDriveItem()
di.SetId(&id)
di.SetParentReference(parentRef)
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetParentReference())
assert.Equal(
t,
ptr.Val(got.GetParentReference().GetId()),
ptr.Val(expected.GetParentReference().GetId()))
assert.Equal(
t,
ptr.Val(got.GetParentReference().GetPath()),
ptr.Val(expected.GetParentReference().GetPath()))
assert.Equal(
t,
ptr.Val(got.GetParentReference().GetName()),
ptr.Val(expected.GetParentReference().GetName()))
assert.Equal(
t,
ptr.Val(got.GetParentReference().GetDriveId()),
ptr.Val(expected.GetParentReference().GetDriveId()))
},
},
{
name: "Created by",
itemFunc: func() models.DriveItemable {
createdBy := models.NewIdentitySet()
createdBy.SetUser(models.NewUser())
createdBy.GetUser().SetAdditionalData(map[string]interface{}{
"email": "email@user",
"displayName": "username",
})
di := models.NewDriveItem()
di.SetId(&id)
di.SetCreatedBy(createdBy)
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetCreatedBy())
require.NotNil(t, got.GetCreatedBy().GetUser())
emailExpected, err := str.AnyValueToString(
"email",
expected.GetCreatedBy().GetUser().GetAdditionalData())
require.NoError(t, err)
emailGot, err := str.AnyValueToString(
"email",
got.GetCreatedBy().GetUser().GetAdditionalData())
require.NoError(t, err)
assert.Equal(t, emailGot, emailExpected)
displayNameExpected, err := str.AnyValueToString(
"displayName",
expected.GetCreatedBy().GetUser().GetAdditionalData())
require.NoError(t, err)
displayNameGot, err := str.AnyValueToString(
"displayName",
got.GetCreatedBy().GetUser().GetAdditionalData())
require.NoError(t, err)
assert.Equal(t, displayNameGot, displayNameExpected)
},
},
{
name: "Created & last modified by users",
itemFunc: func() models.DriveItemable {
createdByUser := models.NewUser()
uid := "creatorUserID"
createdByUser.SetId(&uid)
lastModifiedByUser := models.NewUser()
luid := "lastModifierUserID"
lastModifiedByUser.SetId(&luid)
di := models.NewDriveItem()
di.SetId(&id)
di.SetCreatedByUser(createdByUser)
di.SetLastModifiedByUser(lastModifiedByUser)
return di
},
validateFunc: func(
t *testing.T,
expected models.DriveItemable,
got LiteDriveItemable,
) {
require.NotNil(t, got.GetCreatedByUser())
require.NotNil(t, got.GetLastModifiedByUser())
assert.Equal(
t,
ptr.Val(got.GetCreatedByUser().GetId()),
ptr.Val(expected.GetCreatedByUser().GetId()))
assert.Equal(
t,
ptr.Val(got.GetLastModifiedByUser().GetId()),
ptr.Val(expected.GetLastModifiedByUser().GetId()))
},
},
}
for _, test := range table {
suite.Run(test.name, func() {
expected := test.itemFunc()
got := ToLiteDriveItemable(expected)
test.validateFunc(suite.T(), expected, got)
})
}
}