From 738693a1d79a9ad80e5b974c3b180a8a0b5b91ea Mon Sep 17 00:00:00 2001 From: ashmrtn <3891298+ashmrtn@users.noreply.github.com> Date: Thu, 21 Sep 2023 18:22:53 -0700 Subject: [PATCH] Create and use generic tombstone collection (#4339) Incremental backups requires us to mark some folders as deleted by creating a collection with state `data.DeletedState` This PR creates a simple, generic "tombstone" collection that does just that The PR additionally uses the tombstone collection in place of more complicated implementations where any easy switch is possible. Deleted collections in OneDrive require more work since tests attempt to cast to a concrete type --- #### Does this PR need a docs update or release note? - [ ] :white_check_mark: Yes, it's included - [ ] :clock1: Yes, but in a later PR - [x] :no_entry: No #### Type of change - [ ] :sunflower: Feature - [ ] :bug: Bugfix - [ ] :world_map: Documentation - [ ] :robot: Supportability/Tests - [ ] :computer: CI/Deployment - [x] :broom: Tech Debt/Cleanup #### Issue(s) * #4191 #### Test Plan - [ ] :muscle: Manual - [x] :zap: Unit test - [x] :green_heart: E2E --- src/internal/data/collection_test.go | 14 ++++++++++ src/internal/data/implementations.go | 28 +++++++++++++++++++ .../m365/collection/exchange/backup.go | 15 +--------- src/internal/m365/collection/groups/backup.go | 15 +--------- 4 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/internal/data/collection_test.go b/src/internal/data/collection_test.go index a13201daa..92b0eae77 100644 --- a/src/internal/data/collection_test.go +++ b/src/internal/data/collection_test.go @@ -153,3 +153,17 @@ func (suite *CollectionSuite) TestNewBaseCollection() { }) } } + +func (suite *CollectionSuite) TestNewTombstoneCollection() { + t := suite.T() + + fooP, err := path.Build("t", "u", path.ExchangeService, path.EmailCategory, false, "foo") + require.NoError(t, err, clues.ToCore(err)) + + c := NewTombstoneCollection(fooP, control.Options{}) + assert.Nil(t, c.FullPath(), "full path") + assert.Equal(t, fooP, c.PreviousPath(), "previous path") + assert.Nil(t, c.LocationPath(), "location path") + assert.Equal(t, DeletedState, c.State(), "state") + assert.False(t, c.DoNotMergeItems(), "do not merge") +} diff --git a/src/internal/data/implementations.go b/src/internal/data/implementations.go index 63956c505..c95eb339e 100644 --- a/src/internal/data/implementations.go +++ b/src/internal/data/implementations.go @@ -6,6 +6,7 @@ import ( "github.com/alcionai/clues" "github.com/alcionai/corso/src/pkg/control" + "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" ) @@ -136,3 +137,30 @@ func (col BaseCollection) DoNotMergeItems() bool { func (col BaseCollection) Opts() control.Options { return col.opts } + +// ----------------------------------------------------------------------------- +// tombstoneCollection +// ----------------------------------------------------------------------------- + +func NewTombstoneCollection( + prev path.Path, + opts control.Options, +) *tombstoneCollection { + return &tombstoneCollection{ + BaseCollection: NewBaseCollection(nil, prev, nil, opts, false), + } +} + +// tombstoneCollection is a collection that marks a folder (and folders under it +// if they aren't explicitly noted in other collecteds) as deleted. It doesn't +// contain any items. +type tombstoneCollection struct { + BaseCollection +} + +// Items never returns any data for tombstone collections because the collection +// only denotes the deletion of the current folder and possibly subfolders. All +// items contained in the deleted folder are also deleted. +func (col *tombstoneCollection) Items(context.Context, *fault.Bus) <-chan Item { + return nil +} diff --git a/src/internal/m365/collection/exchange/backup.go b/src/internal/m365/collection/exchange/backup.go index 8ec4818f3..87db96312 100644 --- a/src/internal/m365/collection/exchange/backup.go +++ b/src/internal/m365/collection/exchange/backup.go @@ -241,20 +241,7 @@ func populateCollections( continue } - edc := NewCollection( - data.NewBaseCollection( - nil, // marks the collection as deleted - prevPath, - nil, // tombstones don't need a location - ctrlOpts, - false), - qp.ProtectedResource.ID(), - bh.itemHandler(), - nil, - nil, - false, - statusUpdater) - collections[id] = edc + collections[id] = data.NewTombstoneCollection(prevPath, ctrlOpts) } logger.Ctx(ctx).Infow( diff --git a/src/internal/m365/collection/groups/backup.go b/src/internal/m365/collection/groups/backup.go index 010cb8dd7..1fd8e9b50 100644 --- a/src/internal/m365/collection/groups/backup.go +++ b/src/internal/m365/collection/groups/backup.go @@ -233,20 +233,7 @@ func populateCollections( continue } - edc := NewCollection( - data.NewBaseCollection( - nil, // marks the collection as deleted - prevPath, - nil, // tombstones don't need a location - ctrlOpts, - false), - bh, - qp.ProtectedResource.ID(), - nil, // no items added - nil, // this deletes a directory, so no items deleted either - statusUpdater) - - collections[id] = &edc + collections[id] = data.NewTombstoneCollection(prevPath, ctrlOpts) } logger.Ctx(ctx).Infow(