Use BaseCollection in groups implementation (#4324)

Use common implementation for boiler plate
functionality

---

#### Does this PR need a docs update or release note?

- [ ]  Yes, it's included
- [ ] 🕐 Yes, but in a later PR
- [x]  No

#### Type of change

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

#### Issue(s)

* #4319

#### Test Plan

- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
ashmrtn 2023-09-20 18:04:04 -07:00 committed by GitHub
parent 6159668b1d
commit 231c0a65a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 102 deletions

View File

@ -183,17 +183,18 @@ func populateCollections(
} }
edc := NewCollection( edc := NewCollection(
bh, data.NewBaseCollection(
qp.ProtectedResource.ID(),
currPath, currPath,
prevPath, prevPath,
path.Builder{}.Append(cName), path.Builder{}.Append(cName),
ctrlOpts,
du.Reset),
bh,
qp.ProtectedResource.ID(),
qp.Category, qp.Category,
added, added,
removed, removed,
statusUpdater, statusUpdater)
ctrlOpts,
du.Reset)
collections[cID] = &edc collections[cID] = &edc
@ -234,17 +235,18 @@ func populateCollections(
} }
edc := NewCollection( edc := NewCollection(
bh, data.NewBaseCollection(
qp.ProtectedResource.ID(),
nil, // marks the collection as deleted nil, // marks the collection as deleted
prevPath, prevPath,
nil, // tombstones don't need a location nil, // tombstones don't need a location
ctrlOpts,
false),
bh,
qp.ProtectedResource.ID(),
qp.Category, qp.Category,
nil, // no items added nil, // no items added
nil, // this deletes a directory, so no items deleted either nil, // this deletes a directory, so no items deleted either
statusUpdater, statusUpdater)
ctrlOpts,
false)
collections[id] = &edc collections[id] = &edc
} }

View File

@ -16,7 +16,6 @@ import (
"github.com/alcionai/corso/src/internal/m365/support" "github.com/alcionai/corso/src/internal/m365/support"
"github.com/alcionai/corso/src/internal/observe" "github.com/alcionai/corso/src/internal/observe"
"github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/logger" "github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
@ -35,6 +34,7 @@ const (
) )
type Collection struct { type Collection struct {
data.BaseCollection
protectedResource string protectedResource string
stream chan data.Item stream chan data.Item
@ -47,24 +47,6 @@ type Collection struct {
category path.CategoryType category path.CategoryType
statusUpdater support.StatusUpdater statusUpdater support.StatusUpdater
ctrl control.Options
// FullPath is the current hierarchical path used by this collection.
fullPath path.Path
// PrevPath is the previous hierarchical path used by this collection.
// It may be the same as fullPath, if the folder was not renamed or
// moved. It will be empty on its first retrieval.
prevPath path.Path
// LocationPath contains the path with human-readable display names.
// IE: "/Inbox/Important" instead of "/abcdxyz123/algha=lgkhal=t"
locationPath *path.Builder
state data.CollectionState
// doNotMergeItems should only be true if the old delta token expired.
doNotMergeItems bool
} }
// NewExchangeDataCollection creates an ExchangeDataCollection. // NewExchangeDataCollection creates an ExchangeDataCollection.
@ -74,28 +56,20 @@ type Collection struct {
// If both are populated, then state is either moved (if they differ), // If both are populated, then state is either moved (if they differ),
// or notMoved (if they match). // or notMoved (if they match).
func NewCollection( func NewCollection(
baseCol data.BaseCollection,
getter getChannelMessager, getter getChannelMessager,
protectedResource string, protectedResource string,
curr, prev path.Path,
location *path.Builder,
category path.CategoryType, category path.CategoryType,
added map[string]struct{}, added map[string]struct{},
removed map[string]struct{}, removed map[string]struct{},
statusUpdater support.StatusUpdater, statusUpdater support.StatusUpdater,
ctrlOpts control.Options,
doNotMergeItems bool,
) Collection { ) Collection {
collection := Collection{ collection := Collection{
BaseCollection: baseCol,
added: added, added: added,
category: category, category: category,
ctrl: ctrlOpts,
doNotMergeItems: doNotMergeItems,
fullPath: curr,
getter: getter, getter: getter,
locationPath: location,
prevPath: prev,
removed: removed, removed: removed,
state: data.StateOf(prev, curr),
statusUpdater: statusUpdater, statusUpdater: statusUpdater,
stream: make(chan data.Item, collectionChannelBufferSize), stream: make(chan data.Item, collectionChannelBufferSize),
protectedResource: protectedResource, protectedResource: protectedResource,
@ -111,31 +85,6 @@ func (col *Collection) Items(ctx context.Context, errs *fault.Bus) <-chan data.I
return col.stream return col.stream
} }
// FullPath returns the Collection's fullPath []string
func (col *Collection) FullPath() path.Path {
return col.fullPath
}
// LocationPath produces the Collection's full path, but with display names
// instead of IDs in the folders. Only populated for Calendars.
func (col *Collection) LocationPath() *path.Builder {
return col.locationPath
}
// TODO(ashmrtn): Fill in with previous path once the Controller compares old
// and new folder hierarchies.
func (col Collection) PreviousPath() path.Path {
return col.prevPath
}
func (col Collection) State() data.CollectionState {
return col.state
}
func (col Collection) DoNotMergeItems() bool {
return col.doNotMergeItems
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// items // items
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -214,7 +163,7 @@ func (col *Collection) streamItems(ctx context.Context, errs *fault.Bus) {
defer close(colProgress) defer close(colProgress)
} }
semaphoreCh := make(chan struct{}, col.ctrl.Parallelism.ItemFetch) semaphoreCh := make(chan struct{}, col.Opts().Parallelism.ItemFetch)
defer close(semaphoreCh) defer close(semaphoreCh)
// delete all removed items // delete all removed items
@ -258,7 +207,7 @@ func (col *Collection) streamItems(ctx context.Context, errs *fault.Bus) {
writer := kjson.NewJsonSerializationWriter() writer := kjson.NewJsonSerializationWriter()
defer writer.Close() defer writer.Close()
flds := col.fullPath.Folders() flds := col.FullPath().Folders()
parentFolderID := flds[len(flds)-1] parentFolderID := flds[len(flds)-1]
item, info, err := col.getter.GetChannelMessage( item, info, err := col.getter.GetChannelMessage(

View File

@ -54,30 +54,6 @@ func (suite *CollectionUnitSuite) TestReader_Empty() {
assert.NoError(t, err, clues.ToCore(err)) assert.NoError(t, err, clues.ToCore(err))
} }
func (suite *CollectionUnitSuite) TestCollection_NewCollection() {
t := suite.T()
tenant := "a-tenant"
protectedResource := "a-protectedResource"
folder := "a-folder"
name := "protectedResource"
fullPath, err := path.Build(
tenant,
protectedResource,
path.GroupsService,
path.ChannelMessagesCategory,
false,
folder)
require.NoError(t, err, clues.ToCore(err))
edc := Collection{
protectedResource: name,
fullPath: fullPath,
}
assert.Equal(t, name, edc.protectedResource)
assert.Equal(t, fullPath, edc.FullPath())
}
func (suite *CollectionUnitSuite) TestNewCollection_state() { func (suite *CollectionUnitSuite) TestNewCollection_state() {
fooP, err := path.Build("t", "u", path.GroupsService, path.ChannelMessagesCategory, false, "foo") fooP, err := path.Build("t", "u", path.GroupsService, path.ChannelMessagesCategory, false, "foo")
require.NoError(suite.T(), err, clues.ToCore(err)) require.NoError(suite.T(), err, clues.ToCore(err))
@ -124,18 +100,21 @@ func (suite *CollectionUnitSuite) TestNewCollection_state() {
t := suite.T() t := suite.T()
c := NewCollection( c := NewCollection(
data.NewBaseCollection(
test.curr,
test.prev,
test.loc,
control.DefaultOptions(),
false),
nil, nil,
"g", "g",
test.curr, test.prev, test.loc,
0, 0,
nil, nil, nil, nil,
nil, nil)
control.DefaultOptions(),
false)
assert.Equal(t, test.expect, c.State(), "collection state") assert.Equal(t, test.expect, c.State(), "collection state")
assert.Equal(t, test.curr, c.fullPath, "full path") assert.Equal(t, test.curr, c.FullPath(), "full path")
assert.Equal(t, test.prev, c.prevPath, "prev path") assert.Equal(t, test.prev, c.PreviousPath(), "prev path")
assert.Equal(t, test.loc, c.locationPath, "location path") assert.Equal(t, test.loc, c.LocationPath(), "location path")
}) })
} }
} }
@ -203,13 +182,16 @@ func (suite *CollectionUnitSuite) TestCollection_streamItems() {
defer flush() defer flush()
col := &Collection{ col := &Collection{
BaseCollection: data.NewBaseCollection(
fullPath,
nil,
locPath.ToBuilder(),
control.DefaultOptions(),
false),
added: test.added, added: test.added,
removed: test.removed, removed: test.removed,
ctrl: control.DefaultOptions(),
getter: mock.GetChannelMessage{}, getter: mock.GetChannelMessage{},
stream: make(chan data.Item), stream: make(chan data.Item),
fullPath: fullPath,
locationPath: locPath.ToBuilder(),
statusUpdater: statusUpdater, statusUpdater: statusUpdater,
} }