apply channels and streaming to drive collections
Updates drive collection processing with the new pattern of streaming pages from the api using channels. This is the last in a multipart update that has been separated for ease of review. Everything should now pass.
This commit is contained in:
parent
45aac829dc
commit
c805c8f8e5
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
@ -272,13 +273,6 @@ func (c *Collections) Get(
|
|||||||
excludedItemIDs = map[string]struct{}{}
|
excludedItemIDs = map[string]struct{}{}
|
||||||
oldPrevPaths = oldPrevPathsByDriveID[driveID]
|
oldPrevPaths = oldPrevPathsByDriveID[driveID]
|
||||||
prevDeltaLink = prevDriveIDToDelta[driveID]
|
prevDeltaLink = prevDriveIDToDelta[driveID]
|
||||||
|
|
||||||
// itemCollection is used to identify which collection a
|
|
||||||
// file belongs to. This is useful to delete a file from the
|
|
||||||
// collection it was previously in, in case it was moved to a
|
|
||||||
// different collection within the same delta query
|
|
||||||
// item ID -> item ID
|
|
||||||
itemCollection = map[string]string{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
delete(driveTombstones, driveID)
|
delete(driveTombstones, driveID)
|
||||||
@ -295,13 +289,16 @@ func (c *Collections) Get(
|
|||||||
"previous metadata for drive",
|
"previous metadata for drive",
|
||||||
"num_paths_entries", len(oldPrevPaths))
|
"num_paths_entries", len(oldPrevPaths))
|
||||||
|
|
||||||
items, du, err := c.handler.EnumerateDriveItemsDelta(
|
du, newPrevPaths, err := c.PopulateDriveCollections(
|
||||||
ictx,
|
ctx,
|
||||||
driveID,
|
driveID,
|
||||||
|
driveName,
|
||||||
|
oldPrevPaths,
|
||||||
|
excludedItemIDs,
|
||||||
prevDeltaLink,
|
prevDeltaLink,
|
||||||
api.DefaultDriveItemProps())
|
errs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, clues.Stack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's alright to have an empty folders map (i.e. no folders found) but not
|
// It's alright to have an empty folders map (i.e. no folders found) but not
|
||||||
@ -313,20 +310,6 @@ func (c *Collections) Get(
|
|||||||
driveIDToDeltaLink[driveID] = du.URL
|
driveIDToDeltaLink[driveID] = du.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
newPrevPaths, err := c.UpdateCollections(
|
|
||||||
ctx,
|
|
||||||
driveID,
|
|
||||||
driveName,
|
|
||||||
items,
|
|
||||||
oldPrevPaths,
|
|
||||||
itemCollection,
|
|
||||||
excludedItemIDs,
|
|
||||||
du.Reset,
|
|
||||||
errs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, clues.Stack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid the edge case where there's no paths but we do have a valid delta
|
// Avoid the edge case where there's no paths but we do have a valid delta
|
||||||
// token. We can accomplish this by adding an empty paths map for this
|
// token. We can accomplish this by adding an empty paths map for this
|
||||||
// drive. If we don't have this then the next backup won't use the delta
|
// drive. If we don't have this then the next backup won't use the delta
|
||||||
@ -688,37 +671,104 @@ func (c *Collections) getCollectionPath(
|
|||||||
return collectionPath, nil
|
return collectionPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateCollections initializes and adds the provided drive items to Collections
|
// PopulateDriveCollections initializes and adds the provided drive items to Collections
|
||||||
// A new collection is created for every drive folder (or package).
|
// A new collection is created for every drive folder.
|
||||||
// oldPrevPaths is the unchanged data that was loaded from the metadata file.
|
// oldPrevPaths is the unchanged data that was loaded from the metadata file.
|
||||||
// This map is not modified during the call.
|
// This map is not modified during the call.
|
||||||
// currPrevPaths starts as a copy of oldPaths and is updated as changes are found in
|
// currPrevPaths starts as a copy of oldPaths and is updated as changes are found in
|
||||||
// the returned results. Items are added to this collection throughout the call.
|
// the returned results. Items are added to this collection throughout the call.
|
||||||
// newPrevPaths, ie: the items added during this call, get returned as a map.
|
// newPrevPaths, ie: the items added during this call, get returned as a map.
|
||||||
func (c *Collections) UpdateCollections(
|
func (c *Collections) PopulateDriveCollections(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
driveID, driveName string,
|
driveID, driveName string,
|
||||||
items []models.DriveItemable,
|
|
||||||
oldPrevPaths map[string]string,
|
oldPrevPaths map[string]string,
|
||||||
currPrevPaths map[string]string,
|
excludedItemIDs map[string]struct{},
|
||||||
excluded map[string]struct{},
|
prevDeltaLink string,
|
||||||
invalidPrevDelta bool,
|
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) (map[string]string, error) {
|
) (api.DeltaUpdate, map[string]string, error) {
|
||||||
var (
|
var (
|
||||||
el = errs.Local()
|
el = errs.Local()
|
||||||
newPrevPaths = map[string]string{}
|
newPrevPaths = map[string]string{}
|
||||||
|
invalidPrevDelta = len(prevDeltaLink) == 0
|
||||||
|
ch = make(chan api.NextPage[models.DriveItemable], 1)
|
||||||
|
wg = sync.WaitGroup{}
|
||||||
|
|
||||||
|
// currPrevPaths is used to identify which collection a
|
||||||
|
// file belongs to. This is useful to delete a file from the
|
||||||
|
// collection it was previously in, in case it was moved to a
|
||||||
|
// different collection within the same delta query
|
||||||
|
// item ID -> item ID
|
||||||
|
currPrevPaths = map[string]string{}
|
||||||
)
|
)
|
||||||
|
|
||||||
if !invalidPrevDelta {
|
if !invalidPrevDelta {
|
||||||
maps.Copy(newPrevPaths, oldPrevPaths)
|
maps.Copy(newPrevPaths, oldPrevPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range items {
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
for pg := range ch {
|
||||||
if el.Failure() != nil {
|
if el.Failure() != nil {
|
||||||
break
|
// exhaust the channel to ensure it closes
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pg.Reset {
|
||||||
|
newPrevPaths = map[string]string{}
|
||||||
|
currPrevPaths = map[string]string{}
|
||||||
|
c.CollectionMap[driveID] = map[string]*Collection{}
|
||||||
|
invalidPrevDelta = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range pg.Items {
|
||||||
|
if el.Failure() != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.processItem(
|
||||||
|
ctx,
|
||||||
|
item,
|
||||||
|
driveID,
|
||||||
|
driveName,
|
||||||
|
oldPrevPaths,
|
||||||
|
currPrevPaths,
|
||||||
|
newPrevPaths,
|
||||||
|
excludedItemIDs,
|
||||||
|
invalidPrevDelta,
|
||||||
|
el)
|
||||||
|
if err != nil {
|
||||||
|
el.AddRecoverable(ctx, clues.Stack(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
du, err := c.handler.EnumerateDriveItemsDelta(
|
||||||
|
ctx,
|
||||||
|
ch,
|
||||||
|
driveID,
|
||||||
|
prevDeltaLink)
|
||||||
|
if err != nil {
|
||||||
|
return du, nil, clues.Stack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return du, newPrevPaths, el.Failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collections) processItem(
|
||||||
|
ctx context.Context,
|
||||||
|
item models.DriveItemable,
|
||||||
|
driveID, driveName string,
|
||||||
|
oldPrevPaths, currPrevPaths, newPrevPaths map[string]string,
|
||||||
|
excluded map[string]struct{},
|
||||||
|
invalidPrevDelta bool,
|
||||||
|
skipper fault.AddSkipper,
|
||||||
|
) error {
|
||||||
var (
|
var (
|
||||||
itemID = ptr.Val(item.GetId())
|
itemID = ptr.Val(item.GetId())
|
||||||
itemName = ptr.Val(item.GetName())
|
itemName = ptr.Val(item.GetName())
|
||||||
@ -738,15 +788,15 @@ func (c *Collections) UpdateCollections(
|
|||||||
skip = fault.ContainerSkip(fault.SkipMalware, driveID, itemID, itemName, addtl)
|
skip = fault.ContainerSkip(fault.SkipMalware, driveID, itemID, itemName, addtl)
|
||||||
}
|
}
|
||||||
|
|
||||||
errs.AddSkip(ctx, skip)
|
skipper.AddSkip(ctx, skip)
|
||||||
logger.Ctx(ctx).Infow("malware detected", "item_details", addtl)
|
logger.Ctx(ctx).Infow("malware detected", "item_details", addtl)
|
||||||
|
|
||||||
continue
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deleted file or folder.
|
// Deleted file or folder.
|
||||||
if item.GetDeleted() != nil {
|
if item.GetDeleted() != nil {
|
||||||
if err := c.handleDelete(
|
err := c.handleDelete(
|
||||||
itemID,
|
itemID,
|
||||||
driveID,
|
driveID,
|
||||||
oldPrevPaths,
|
oldPrevPaths,
|
||||||
@ -754,26 +804,22 @@ func (c *Collections) UpdateCollections(
|
|||||||
newPrevPaths,
|
newPrevPaths,
|
||||||
isFolder,
|
isFolder,
|
||||||
excluded,
|
excluded,
|
||||||
invalidPrevDelta); err != nil {
|
invalidPrevDelta)
|
||||||
return nil, clues.Stack(err).WithClues(ictx)
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
return clues.Stack(err).WithClues(ictx).OrNil()
|
||||||
}
|
}
|
||||||
|
|
||||||
collectionPath, err := c.getCollectionPath(driveID, item)
|
collectionPath, err := c.getCollectionPath(driveID, item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
el.AddRecoverable(ctx, clues.Stack(err).
|
return clues.Stack(err).
|
||||||
WithClues(ictx).
|
WithClues(ictx).
|
||||||
Label(fault.LabelForceNoBackupCreation))
|
Label(fault.LabelForceNoBackupCreation)
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip items that don't match the folder selectors we were given.
|
// Skip items that don't match the folder selectors we were given.
|
||||||
if shouldSkip(ctx, collectionPath, c.handler, driveName) {
|
if shouldSkip(ctx, collectionPath, c.handler, driveName) {
|
||||||
logger.Ctx(ictx).Debugw("path not selected", "skipped_path", collectionPath.String())
|
logger.Ctx(ictx).Debugw("path not selected", "skipped_path", collectionPath.String())
|
||||||
continue
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@ -785,9 +831,9 @@ func (c *Collections) UpdateCollections(
|
|||||||
if ok {
|
if ok {
|
||||||
prevPath, err = path.FromDataLayerPath(prevPathStr, false)
|
prevPath, err = path.FromDataLayerPath(prevPathStr, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
el.AddRecoverable(ctx, clues.Wrap(err, "invalid previous path").
|
return clues.Wrap(err, "invalid previous path").
|
||||||
WithClues(ictx).
|
WithClues(ictx).
|
||||||
With("prev_path_string", path.LoggableDir(prevPathStr)))
|
With("prev_path_string", path.LoggableDir(prevPathStr))
|
||||||
}
|
}
|
||||||
} else if item.GetRoot() != nil {
|
} else if item.GetRoot() != nil {
|
||||||
// Root doesn't move or get renamed.
|
// Root doesn't move or get renamed.
|
||||||
@ -799,13 +845,17 @@ func (c *Collections) UpdateCollections(
|
|||||||
// update newPaths so we don't accidentally clobber previous deletes.
|
// update newPaths so we don't accidentally clobber previous deletes.
|
||||||
updatePath(newPrevPaths, itemID, collectionPath.String())
|
updatePath(newPrevPaths, itemID, collectionPath.String())
|
||||||
|
|
||||||
found, err := updateCollectionPaths(driveID, itemID, c.CollectionMap, collectionPath)
|
found, err := updateCollectionPaths(
|
||||||
|
driveID,
|
||||||
|
itemID,
|
||||||
|
c.CollectionMap,
|
||||||
|
collectionPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, clues.Stack(err).WithClues(ictx)
|
return clues.Stack(err).WithClues(ictx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if found {
|
if found {
|
||||||
continue
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
colScope := CollectionScopeFolder
|
colScope := CollectionScopeFolder
|
||||||
@ -825,7 +875,7 @@ func (c *Collections) UpdateCollections(
|
|||||||
invalidPrevDelta,
|
invalidPrevDelta,
|
||||||
nil)
|
nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, clues.Stack(err).WithClues(ictx)
|
return clues.Stack(err).WithClues(ictx)
|
||||||
}
|
}
|
||||||
|
|
||||||
col.driveName = driveName
|
col.driveName = driveName
|
||||||
@ -834,7 +884,7 @@ func (c *Collections) UpdateCollections(
|
|||||||
c.NumContainers++
|
c.NumContainers++
|
||||||
|
|
||||||
if item.GetRoot() != nil {
|
if item.GetRoot() != nil {
|
||||||
continue
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an entry to fetch permissions into this collection. This assumes
|
// Add an entry to fetch permissions into this collection. This assumes
|
||||||
@ -847,7 +897,7 @@ func (c *Collections) UpdateCollections(
|
|||||||
case item.GetFile() != nil:
|
case item.GetFile() != nil:
|
||||||
// Deletions are handled above so this is just moves/renames.
|
// Deletions are handled above so this is just moves/renames.
|
||||||
if len(ptr.Val(item.GetParentReference().GetId())) == 0 {
|
if len(ptr.Val(item.GetParentReference().GetId())) == 0 {
|
||||||
return nil, clues.New("file without parent ID").WithClues(ictx)
|
return clues.New("file without parent ID").WithClues(ictx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the collection for this item.
|
// Get the collection for this item.
|
||||||
@ -856,7 +906,7 @@ func (c *Collections) UpdateCollections(
|
|||||||
|
|
||||||
collection, ok := c.CollectionMap[driveID][parentID]
|
collection, ok := c.CollectionMap[driveID][parentID]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, clues.New("item seen before parent folder").WithClues(ictx)
|
return clues.New("item seen before parent folder").WithClues(ictx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will only kick in if the file was moved multiple times
|
// This will only kick in if the file was moved multiple times
|
||||||
@ -866,13 +916,13 @@ func (c *Collections) UpdateCollections(
|
|||||||
if ok {
|
if ok {
|
||||||
prevColl, found := c.CollectionMap[driveID][prevParentContainerID]
|
prevColl, found := c.CollectionMap[driveID][prevParentContainerID]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, clues.New("previous collection not found").
|
return clues.New("previous collection not found").
|
||||||
With("prev_parent_container_id", prevParentContainerID).
|
With("prev_parent_container_id", prevParentContainerID).
|
||||||
WithClues(ictx)
|
WithClues(ictx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok := prevColl.Remove(itemID); !ok {
|
if ok := prevColl.Remove(itemID); !ok {
|
||||||
return nil, clues.New("removing item from prev collection").
|
return clues.New("removing item from prev collection").
|
||||||
With("prev_parent_container_id", prevParentContainerID).
|
With("prev_parent_container_id", prevParentContainerID).
|
||||||
WithClues(ictx)
|
WithClues(ictx)
|
||||||
}
|
}
|
||||||
@ -899,13 +949,12 @@ func (c *Collections) UpdateCollections(
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
el.AddRecoverable(ictx, clues.New("item is neither folder nor file").
|
return clues.New("item is neither folder nor file").
|
||||||
WithClues(ictx).
|
WithClues(ictx).
|
||||||
Label(fault.LabelForceNoBackupCreation))
|
Label(fault.LabelForceNoBackupCreation)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newPrevPaths, el.Failure()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type dirScopeChecker interface {
|
type dirScopeChecker interface {
|
||||||
@ -913,7 +962,12 @@ type dirScopeChecker interface {
|
|||||||
IncludesDir(dir string) bool
|
IncludesDir(dir string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldSkip(ctx context.Context, drivePath path.Path, dsc dirScopeChecker, driveName string) bool {
|
func shouldSkip(
|
||||||
|
ctx context.Context,
|
||||||
|
drivePath path.Path,
|
||||||
|
dsc dirScopeChecker,
|
||||||
|
driveName string,
|
||||||
|
) bool {
|
||||||
return !includePath(ctx, dsc, drivePath) ||
|
return !includePath(ctx, dsc, drivePath) ||
|
||||||
(drivePath.Category() == path.LibrariesCategory && restrictedDirectory == driveName)
|
(drivePath.Category() == path.LibrariesCategory && restrictedDirectory == driveName)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -119,7 +119,7 @@ func getDelList(files ...string) map[string]struct{} {
|
|||||||
return delList
|
return delList
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *OneDriveCollectionsUnitSuite) TestUpdateCollections() {
|
func (suite *OneDriveCollectionsUnitSuite) TestPopulateDriveCollections() {
|
||||||
anyFolder := (&selectors.OneDriveBackup{}).Folders(selectors.Any())[0]
|
anyFolder := (&selectors.OneDriveBackup{}).Folders(selectors.Any())[0]
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -690,7 +690,9 @@ func (suite *OneDriveCollectionsUnitSuite) TestUpdateCollections() {
|
|||||||
expectedItemCount: 0,
|
expectedItemCount: 0,
|
||||||
expectedFileCount: 0,
|
expectedFileCount: 0,
|
||||||
expectedContainerCount: 1,
|
expectedContainerCount: 1,
|
||||||
expectedPrevPaths: nil,
|
expectedPrevPaths: map[string]string{
|
||||||
|
"root": expectedPath(""),
|
||||||
|
},
|
||||||
expectedExcludes: map[string]struct{}{},
|
expectedExcludes: map[string]struct{}{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -732,15 +734,31 @@ func (suite *OneDriveCollectionsUnitSuite) TestUpdateCollections() {
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
mbh = mock.DefaultOneDriveBH(user)
|
||||||
|
du = api.DeltaUpdate{
|
||||||
|
URL: "notempty",
|
||||||
|
Reset: false,
|
||||||
|
}
|
||||||
excludes = map[string]struct{}{}
|
excludes = map[string]struct{}{}
|
||||||
currPrevPaths = map[string]string{}
|
|
||||||
errs = fault.New(true)
|
errs = fault.New(true)
|
||||||
)
|
)
|
||||||
|
|
||||||
maps.Copy(currPrevPaths, test.inputFolderMap)
|
mbh.DriveItemEnumeration = mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
|
driveID: {
|
||||||
|
{Items: test.items},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{driveID: du},
|
||||||
|
}
|
||||||
|
|
||||||
|
sel := selectors.NewOneDriveBackup([]string{user})
|
||||||
|
sel.Include([]selectors.OneDriveScope{test.scope})
|
||||||
|
|
||||||
|
mbh.Sel = sel.Selector
|
||||||
|
|
||||||
c := NewCollections(
|
c := NewCollections(
|
||||||
&itemBackupHandler{api.Drives{}, user, test.scope},
|
mbh,
|
||||||
tenant,
|
tenant,
|
||||||
idname.NewProvider(user, user),
|
idname.NewProvider(user, user),
|
||||||
nil,
|
nil,
|
||||||
@ -748,18 +766,19 @@ func (suite *OneDriveCollectionsUnitSuite) TestUpdateCollections() {
|
|||||||
|
|
||||||
c.CollectionMap[driveID] = map[string]*Collection{}
|
c.CollectionMap[driveID] = map[string]*Collection{}
|
||||||
|
|
||||||
newPrevPaths, err := c.UpdateCollections(
|
_, newPrevPaths, err := c.PopulateDriveCollections(
|
||||||
ctx,
|
ctx,
|
||||||
driveID,
|
driveID,
|
||||||
"General",
|
"General",
|
||||||
test.items,
|
|
||||||
test.inputFolderMap,
|
test.inputFolderMap,
|
||||||
currPrevPaths,
|
|
||||||
excludes,
|
excludes,
|
||||||
false,
|
"smarf",
|
||||||
errs)
|
errs)
|
||||||
test.expect(t, err, clues.ToCore(err))
|
test.expect(t, err, clues.ToCore(err))
|
||||||
assert.Equal(t, len(test.expectedCollectionIDs), len(c.CollectionMap[driveID]), "total collections")
|
assert.ElementsMatch(
|
||||||
|
t,
|
||||||
|
maps.Keys(test.expectedCollectionIDs),
|
||||||
|
maps.Keys(c.CollectionMap[driveID]))
|
||||||
assert.Equal(t, test.expectedItemCount, c.NumItems, "item count")
|
assert.Equal(t, test.expectedItemCount, c.NumItems, "item count")
|
||||||
assert.Equal(t, test.expectedFileCount, c.NumFiles, "file count")
|
assert.Equal(t, test.expectedFileCount, c.NumFiles, "file count")
|
||||||
assert.Equal(t, test.expectedContainerCount, c.NumContainers, "container count")
|
assert.Equal(t, test.expectedContainerCount, c.NumContainers, "container count")
|
||||||
@ -1166,7 +1185,6 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
tenant = "a-tenant"
|
tenant = "a-tenant"
|
||||||
user = "a-user"
|
user = "a-user"
|
||||||
empty = ""
|
empty = ""
|
||||||
next = "next"
|
|
||||||
delta = "delta1"
|
delta = "delta1"
|
||||||
delta2 = "delta2"
|
delta2 = "delta2"
|
||||||
)
|
)
|
||||||
@ -1208,7 +1226,7 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
drives []models.Driveable
|
drives []models.Driveable
|
||||||
items map[string][]apiMock.PagerResult[models.DriveItemable]
|
enumerator mock.EnumeratesDriveItemsDelta[models.DriveItemable]
|
||||||
canUsePreviousBackup bool
|
canUsePreviousBackup bool
|
||||||
errCheck assert.ErrorAssertionFunc
|
errCheck assert.ErrorAssertionFunc
|
||||||
prevFolderPaths map[string]map[string]string
|
prevFolderPaths map[string]map[string]string
|
||||||
@ -1227,16 +1245,19 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive_OneItemPage_DelFileOnly_NoFolders_NoErrors",
|
name: "OneDrive_OneItemPage_DelFileOnly_NoFolders_NoErrors",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"), // will be present, not needed
|
driveRootItem("root"), // will be present, not needed
|
||||||
delItem("file", driveBasePath1, "root", true, false, false),
|
delItem("file", driveBasePath1, "root", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -1259,16 +1280,19 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive_OneItemPage_NoFolderDeltas_NoErrors",
|
name: "OneDrive_OneItemPage_NoFolderDeltas_NoErrors",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("file", "file", driveBasePath1, "root", true, false, false),
|
driveItem("file", "file", driveBasePath1, "root", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -1291,18 +1315,20 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive_OneItemPage_NoErrors",
|
name: "OneDrive_OneItemPage_NoErrors",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -1329,19 +1355,21 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive_OneItemPage_NoErrors_FileRenamedMultiple",
|
name: "OneDrive_OneItemPage_NoErrors_FileRenamedMultiple",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
driveItem("file", "file2", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file2", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -1368,18 +1396,21 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive_OneItemPage_NoErrors_FileMovedMultiple",
|
name: "OneDrive_OneItemPage_NoErrors_FileMovedMultiple",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
driveItem("file", "file2", driveBasePath1, "root", true, false, false),
|
driveItem("file", "file2", driveBasePath1, "root", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -1408,18 +1439,20 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive_OneItemPage_EmptyDelta_NoErrors",
|
name: "OneDrive_OneItemPage_EmptyDelta_NoErrors",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &empty, // probably will never happen with graph
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: empty, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -1446,28 +1479,151 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive_TwoItemPages_NoErrors",
|
name: "OneDrive_TwoItemPages_NoErrors",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
},
|
||||||
NextLink: &next,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file2", "file2", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file2", "file2", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
|
canUsePreviousBackup: true,
|
||||||
|
errCheck: assert.NoError,
|
||||||
|
prevFolderPaths: map[string]map[string]string{
|
||||||
|
driveID1: {},
|
||||||
|
},
|
||||||
|
expectedCollections: map[string]map[data.CollectionState][]string{
|
||||||
|
rootFolderPath1: {data.NewState: {}},
|
||||||
|
folderPath1: {data.NewState: {"folder", "file", "file2"}},
|
||||||
|
},
|
||||||
|
expectedDeltaURLs: map[string]string{
|
||||||
|
driveID1: delta,
|
||||||
|
},
|
||||||
|
expectedFolderPaths: map[string]map[string]string{
|
||||||
|
driveID1: {
|
||||||
|
"root": rootFolderPath1,
|
||||||
|
"folder": folderPath1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedDelList: pmMock.NewPrefixMap(map[string]map[string]struct{}{}),
|
||||||
|
doNotMergeItems: map[string]bool{
|
||||||
|
rootFolderPath1: true,
|
||||||
|
folderPath1: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OneDrive_TwoItemPages_WithReset",
|
||||||
|
drives: []models.Driveable{drive1},
|
||||||
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
|
driveID1: {
|
||||||
|
{
|
||||||
|
Items: []models.DriveItemable{
|
||||||
|
driveRootItem("root"),
|
||||||
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Items: []models.DriveItemable{},
|
||||||
|
Reset: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Items: []models.DriveItemable{
|
||||||
|
driveRootItem("root"),
|
||||||
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Items: []models.DriveItemable{
|
||||||
|
driveRootItem("root"),
|
||||||
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
|
driveItem("file2", "file2", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
|
canUsePreviousBackup: true,
|
||||||
|
errCheck: assert.NoError,
|
||||||
|
prevFolderPaths: map[string]map[string]string{
|
||||||
|
driveID1: {},
|
||||||
|
},
|
||||||
|
expectedCollections: map[string]map[data.CollectionState][]string{
|
||||||
|
rootFolderPath1: {data.NewState: {}},
|
||||||
|
folderPath1: {data.NewState: {"folder", "file", "file2"}},
|
||||||
|
},
|
||||||
|
expectedDeltaURLs: map[string]string{
|
||||||
|
driveID1: delta,
|
||||||
|
},
|
||||||
|
expectedFolderPaths: map[string]map[string]string{
|
||||||
|
driveID1: {
|
||||||
|
"root": rootFolderPath1,
|
||||||
|
"folder": folderPath1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedDelList: pmMock.NewPrefixMap(map[string]map[string]struct{}{}),
|
||||||
|
doNotMergeItems: map[string]bool{
|
||||||
|
rootFolderPath1: true,
|
||||||
|
folderPath1: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OneDrive_TwoItemPages_WithResetCombinedWithItems",
|
||||||
|
drives: []models.Driveable{drive1},
|
||||||
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
|
driveID1: {
|
||||||
|
{
|
||||||
|
Items: []models.DriveItemable{
|
||||||
|
driveRootItem("root"),
|
||||||
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Items: []models.DriveItemable{
|
||||||
|
driveRootItem("root"),
|
||||||
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
|
},
|
||||||
|
Reset: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Items: []models.DriveItemable{
|
||||||
|
driveRootItem("root"),
|
||||||
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
|
driveItem("file2", "file2", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
@ -1498,29 +1654,28 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
drive1,
|
drive1,
|
||||||
drive2,
|
drive2,
|
||||||
},
|
},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
driveID2: {
|
driveID2: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root2"),
|
driveRootItem("root2"),
|
||||||
driveItem("folder2", "folder", driveBasePath2, "root2", false, true, false),
|
driveItem("folder2", "folder", driveBasePath2, "root2", false, true, false),
|
||||||
driveItem("file2", "file", driveBasePath2+"/folder", "folder2", true, false, false),
|
driveItem("file2", "file", driveBasePath2+"/folder", "folder2", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta2,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
driveID2: {URL: delta2, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -1562,29 +1717,28 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
drive1,
|
drive1,
|
||||||
drive2,
|
drive2,
|
||||||
},
|
},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
driveID2: {
|
driveID2: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath2, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath2, "root", false, true, false),
|
||||||
driveItem("file2", "file", driveBasePath2+"/folder", "folder", true, false, false),
|
driveItem("file2", "file", driveBasePath2+"/folder", "folder", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta2,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
driveID2: {URL: delta2, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -1623,12 +1777,16 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive_OneItemPage_Errors",
|
name: "OneDrive_OneItemPage_Errors",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{}},
|
||||||
Err: assert.AnError,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: assert.AnError},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: false,
|
canUsePreviousBackup: false,
|
||||||
errCheck: assert.Error,
|
errCheck: assert.Error,
|
||||||
@ -1641,37 +1799,41 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
expectedDelList: nil,
|
expectedDelList: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OneDrive_TwoItemPage_NoDeltaError",
|
name: "OneDrive_OneItemPage_InvalidPrevDelta_DeleteNonExistentFolder",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{},
|
||||||
driveRootItem("root"),
|
Reset: true,
|
||||||
driveItem("file", "file", driveBasePath1, "root", true, false, false),
|
|
||||||
},
|
|
||||||
NextLink: &next,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder2", "folder2", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file2", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder2", "folder2", true, false, false),
|
||||||
},
|
|
||||||
DeltaLink: &delta,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
"root": rootFolderPath1,
|
"root": rootFolderPath1,
|
||||||
|
"folder": folderPath1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCollections: map[string]map[data.CollectionState][]string{
|
expectedCollections: map[string]map[data.CollectionState][]string{
|
||||||
rootFolderPath1: {data.NotMovedState: {"file"}},
|
rootFolderPath1: {data.NewState: {}},
|
||||||
expectedPath1("/folder"): {data.NewState: {"folder", "file2"}},
|
expectedPath1("/folder"): {data.DeletedState: {}},
|
||||||
|
expectedPath1("/folder2"): {data.NewState: {"folder2", "file"}},
|
||||||
},
|
},
|
||||||
expectedDeltaURLs: map[string]string{
|
expectedDeltaURLs: map[string]string{
|
||||||
driveID1: delta,
|
driveID1: delta,
|
||||||
@ -1679,30 +1841,40 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
expectedFolderPaths: map[string]map[string]string{
|
expectedFolderPaths: map[string]map[string]string{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
"root": rootFolderPath1,
|
"root": rootFolderPath1,
|
||||||
"folder": folderPath1,
|
"folder2": expectedPath1("/folder2"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedDelList: pmMock.NewPrefixMap(map[string]map[string]struct{}{
|
expectedDelList: pmMock.NewPrefixMap(map[string]map[string]struct{}{}),
|
||||||
rootFolderPath1: getDelList("file", "file2"),
|
doNotMergeItems: map[string]bool{
|
||||||
}),
|
rootFolderPath1: true,
|
||||||
doNotMergeItems: map[string]bool{},
|
folderPath1: true,
|
||||||
|
expectedPath1("/folder2"): true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OneDrive_OneItemPage_InvalidPrevDelta_DeleteNonExistentFolder",
|
name: "OneDrive_OneItemPage_InvalidPrevDeltaCombinedWithItems_DeleteNonExistentFolder",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{},
|
||||||
|
Reset: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder2", "folder2", driveBasePath1, "root", false, true, false),
|
driveItem("folder2", "folder2", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder2", "folder2", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder2", "folder2", true, false, false),
|
||||||
},
|
},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
@ -1735,19 +1907,38 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive_OneItemPage_InvalidPrevDelta_AnotherFolderAtDeletedLocation",
|
name: "OneDrive_OneItemPage_InvalidPrevDelta_AnotherFolderAtDeletedLocation",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
// on the first page, if this is the total data, we'd expect both folder and folder2
|
||||||
|
// since new previousPaths merge with the old previousPaths.
|
||||||
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder2", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder2", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder2", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder2", true, false, false),
|
||||||
},
|
},
|
||||||
DeltaLink: &delta,
|
},
|
||||||
ResetDelta: true,
|
{
|
||||||
|
Items: []models.DriveItemable{},
|
||||||
|
Reset: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// but after a delta reset, we treat this as the total end set of folders, which means
|
||||||
|
// we don't expect folder to exist any longer.
|
||||||
|
Items: []models.DriveItemable{
|
||||||
|
driveRootItem("root"),
|
||||||
|
driveItem("folder2", "folder", driveBasePath1, "root", false, true, false),
|
||||||
|
driveItem("file", "file", driveBasePath1+"/folder", "folder2", true, false, false),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
@ -1783,29 +1974,32 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "OneDrive Two Item Pages with Malware",
|
name: "OneDrive Two Item Pages with Malware",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
malwareItem("malware", "malware", driveBasePath1+"/folder", "folder", true, false, false),
|
malwareItem("malware", "malware", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
},
|
||||||
NextLink: &next,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file2", "file2", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file2", "file2", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
malwareItem("malware2", "malware2", driveBasePath1+"/folder", "folder", true, false, false),
|
malwareItem("malware2", "malware2", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
@ -1832,31 +2026,39 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
expectedSkippedCount: 2,
|
expectedSkippedCount: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "One Drive Deleted Folder In New Results",
|
name: "One Drive Deleted Folder In New Results With Invalid Delta",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
driveItem("folder2", "folder2", driveBasePath1, "root", false, true, false),
|
driveItem("folder2", "folder2", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file2", "file2", driveBasePath1+"/folder2", "folder2", true, false, false),
|
driveItem("file2", "file2", driveBasePath1+"/folder2", "folder2", true, false, false),
|
||||||
},
|
},
|
||||||
NextLink: &next,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Reset: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
delItem("folder2", driveBasePath1, "root", false, true, false),
|
delItem("folder2", driveBasePath1, "root", false, true, false),
|
||||||
delItem("file2", driveBasePath1, "root", true, false, false),
|
delItem("file2", driveBasePath1, "root", true, false, false),
|
||||||
},
|
},
|
||||||
DeltaLink: &delta2,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta2, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
@ -1888,20 +2090,25 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "One Drive Random Folder Delete",
|
name: "One Drive Folder Delete After Invalid Delta",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
delItem("folder", driveBasePath1, "root", false, true, false),
|
delItem("folder", driveBasePath1, "root", false, true, false),
|
||||||
},
|
},
|
||||||
DeltaLink: &delta,
|
Reset: true,
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
@ -1929,20 +2136,25 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "One Drive Random Item Delete",
|
name: "One Drive Item Delete After Invalid Delta",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
delItem("file", driveBasePath1, "root", true, false, false),
|
delItem("file", driveBasePath1, "root", true, false, false),
|
||||||
},
|
},
|
||||||
DeltaLink: &delta,
|
Reset: true,
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
@ -1969,27 +2181,30 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "One Drive Folder Made And Deleted",
|
name: "One Drive Folder Made And Deleted",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
},
|
||||||
NextLink: &next,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
delItem("folder", driveBasePath1, "root", false, true, false),
|
delItem("folder", driveBasePath1, "root", false, true, false),
|
||||||
delItem("file", driveBasePath1, "root", true, false, false),
|
delItem("file", driveBasePath1, "root", true, false, false),
|
||||||
},
|
},
|
||||||
DeltaLink: &delta2,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta2, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
@ -2014,26 +2229,29 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "One Drive Item Made And Deleted",
|
name: "One Drive Item Made And Deleted",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
driveItem("folder", "folder", driveBasePath1, "root", false, true, false),
|
||||||
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
driveItem("file", "file", driveBasePath1+"/folder", "folder", true, false, false),
|
||||||
},
|
},
|
||||||
NextLink: &next,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Values: []models.DriveItemable{
|
Items: []models.DriveItemable{
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
delItem("file", driveBasePath1, "root", true, false, false),
|
delItem("file", driveBasePath1, "root", true, false, false),
|
||||||
},
|
},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
prevFolderPaths: map[string]map[string]string{
|
prevFolderPaths: map[string]map[string]string{
|
||||||
@ -2061,17 +2279,19 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "One Drive Random Folder Delete",
|
name: "One Drive Random Folder Delete",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
delItem("folder", driveBasePath1, "root", false, true, false),
|
delItem("folder", driveBasePath1, "root", false, true, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -2097,17 +2317,19 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "One Drive Random Item Delete",
|
name: "One Drive Random Item Delete",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"),
|
driveRootItem("root"),
|
||||||
delItem("file", driveBasePath1, "root", true, false, false),
|
delItem("file", driveBasePath1, "root", true, false, false),
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
ResetDelta: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta, Reset: true},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -2133,15 +2355,18 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
{
|
{
|
||||||
name: "TwoPriorDrives_OneTombstoned",
|
name: "TwoPriorDrives_OneTombstoned",
|
||||||
drives: []models.Driveable{drive1},
|
drives: []models.Driveable{drive1},
|
||||||
items: map[string][]apiMock.PagerResult[models.DriveItemable]{
|
enumerator: mock.EnumeratesDriveItemsDelta[models.DriveItemable]{
|
||||||
|
Pages: map[string][]api.NextPage[models.DriveItemable]{
|
||||||
driveID1: {
|
driveID1: {
|
||||||
{
|
{Items: []models.DriveItemable{
|
||||||
Values: []models.DriveItemable{
|
|
||||||
driveRootItem("root"), // will be present
|
driveRootItem("root"), // will be present
|
||||||
},
|
}},
|
||||||
DeltaLink: &delta,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DeltaUpdate: map[string]api.DeltaUpdate{
|
||||||
|
driveID1: {URL: delta},
|
||||||
|
},
|
||||||
|
Err: map[string]error{driveID1: nil},
|
||||||
},
|
},
|
||||||
canUsePreviousBackup: true,
|
canUsePreviousBackup: true,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
@ -2176,18 +2401,9 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
itemPagers := map[string]api.DeltaPager[models.DriveItemable]{}
|
|
||||||
|
|
||||||
for driveID := range test.items {
|
|
||||||
itemPagers[driveID] = &apiMock.DeltaPager[models.DriveItemable]{
|
|
||||||
ToReturn: test.items[driveID],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mbh := mock.DefaultOneDriveBH("a-user")
|
mbh := mock.DefaultOneDriveBH("a-user")
|
||||||
mbh.DrivePagerV = mockDrivePager
|
mbh.DrivePagerV = mockDrivePager
|
||||||
mbh.ItemPagerV = itemPagers
|
mbh.DriveItemEnumeration = test.enumerator
|
||||||
mbh.DriveItemEnumeration = mock.PagerResultToEDID(test.items)
|
|
||||||
|
|
||||||
c := NewCollections(
|
c := NewCollections(
|
||||||
mbh,
|
mbh,
|
||||||
@ -2262,10 +2478,10 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() {
|
|||||||
|
|
||||||
collectionCount++
|
collectionCount++
|
||||||
|
|
||||||
// TODO(ashmrtn): We should really be getting items in the collection
|
// TODO: We should really be getting items in the collection
|
||||||
// via the Items() channel, but we don't have a way to mock out the
|
// via the Items() channel. The lack of that makes this check a bit more
|
||||||
// actual item fetch yet (mostly wiring issues). The lack of that makes
|
// bittle since internal details can change. The wiring to support
|
||||||
// this check a bit more bittle since internal details can change.
|
// mocked GetItems is available. We just haven't plugged it in yet.
|
||||||
col, ok := baseCol.(*Collection)
|
col, ok := baseCol.(*Collection)
|
||||||
require.True(t, ok, "getting onedrive.Collection handle")
|
require.True(t, ok, "getting onedrive.Collection handle")
|
||||||
|
|
||||||
|
|||||||
@ -292,8 +292,8 @@ func (m GetsItem) GetItem(
|
|||||||
// Enumerates Drive Items
|
// Enumerates Drive Items
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
type NextPage[T any] struct {
|
type NextPage struct {
|
||||||
Items []T
|
Items []models.DriveItemable
|
||||||
Reset bool
|
Reset bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +305,7 @@ var _ api.NextPageResulter[models.DriveItemable] = &DriveItemsDeltaPager{}
|
|||||||
|
|
||||||
type DriveItemsDeltaPager struct {
|
type DriveItemsDeltaPager struct {
|
||||||
Idx int
|
Idx int
|
||||||
Pages []NextPage[models.DriveItemable]
|
Pages []NextPage
|
||||||
DeltaUpdate api.DeltaUpdate
|
DeltaUpdate api.DeltaUpdate
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/common/idname"
|
"github.com/alcionai/corso/src/internal/common/idname"
|
||||||
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
||||||
odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts"
|
odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts"
|
||||||
|
"github.com/alcionai/corso/src/internal/m365/service/onedrive/mock"
|
||||||
"github.com/alcionai/corso/src/internal/tester"
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
"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"
|
||||||
@ -90,16 +91,29 @@ func (suite *LibrariesBackupUnitSuite) TestUpdateCollections() {
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
mbh = mock.DefaultSharePointBH(siteID)
|
||||||
|
du = api.DeltaUpdate{
|
||||||
|
URL: "notempty",
|
||||||
|
Reset: false,
|
||||||
|
}
|
||||||
paths = map[string]string{}
|
paths = map[string]string{}
|
||||||
currPaths = map[string]string{}
|
|
||||||
excluded = map[string]struct{}{}
|
excluded = map[string]struct{}{}
|
||||||
collMap = map[string]map[string]*drive.Collection{
|
collMap = map[string]map[string]*drive.Collection{
|
||||||
driveID: {},
|
driveID: {},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
mbh.DriveItemEnumeration = mock.EnumerateItemsDeltaByDrive{
|
||||||
|
DrivePagers: map[string]mock.DriveItemsDeltaPager{
|
||||||
|
driveID: mock.DriveItemsDeltaPager{
|
||||||
|
Pages: []mock.NextPage{{Items: test.items}},
|
||||||
|
DeltaUpdate: du,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
c := drive.NewCollections(
|
c := drive.NewCollections(
|
||||||
drive.NewLibraryBackupHandler(api.Drives{}, siteID, test.scope, path.SharePointService),
|
mbh,
|
||||||
tenantID,
|
tenantID,
|
||||||
idname.NewProvider(siteID, siteID),
|
idname.NewProvider(siteID, siteID),
|
||||||
nil,
|
nil,
|
||||||
@ -107,15 +121,13 @@ func (suite *LibrariesBackupUnitSuite) TestUpdateCollections() {
|
|||||||
|
|
||||||
c.CollectionMap = collMap
|
c.CollectionMap = collMap
|
||||||
|
|
||||||
_, err := c.UpdateCollections(
|
_, _, err := c.PopulateDriveCollections(
|
||||||
ctx,
|
ctx,
|
||||||
driveID,
|
driveID,
|
||||||
"General",
|
"General",
|
||||||
test.items,
|
|
||||||
paths,
|
paths,
|
||||||
currPaths,
|
|
||||||
excluded,
|
excluded,
|
||||||
true,
|
"",
|
||||||
fault.New(true))
|
fault.New(true))
|
||||||
|
|
||||||
test.expect(t, err, clues.ToCore(err))
|
test.expect(t, err, clues.ToCore(err))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user