Move BaseCollection to different package (#4322)
Prep for use in other packages. Removed tests were covered by other code --- #### 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:
parent
c1ec3c6648
commit
f767b67eca
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"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/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -70,3 +71,84 @@ func (suite *CollectionSuite) TestStateOf() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *CollectionSuite) TestNewBaseCollection() {
|
||||||
|
fooP, err := path.Build("t", "u", path.ExchangeService, path.EmailCategory, false, "foo")
|
||||||
|
require.NoError(suite.T(), err, clues.ToCore(err))
|
||||||
|
barP, err := path.Build("t", "u", path.ExchangeService, path.EmailCategory, false, "bar")
|
||||||
|
require.NoError(suite.T(), err, clues.ToCore(err))
|
||||||
|
preP, err := path.Build("_t", "_u", path.ExchangeService, path.EmailCategory, false, "foo")
|
||||||
|
require.NoError(suite.T(), err, clues.ToCore(err))
|
||||||
|
|
||||||
|
loc := path.Builder{}.Append("foo")
|
||||||
|
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
current path.Path
|
||||||
|
previous path.Path
|
||||||
|
doNotMerge bool
|
||||||
|
|
||||||
|
expectCurrent path.Path
|
||||||
|
expectPrev path.Path
|
||||||
|
expectState CollectionState
|
||||||
|
expectDoNotMerge bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "NotMoved DoNotMerge",
|
||||||
|
current: fooP,
|
||||||
|
previous: fooP,
|
||||||
|
doNotMerge: true,
|
||||||
|
expectCurrent: fooP,
|
||||||
|
expectPrev: fooP,
|
||||||
|
expectState: NotMovedState,
|
||||||
|
expectDoNotMerge: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Moved",
|
||||||
|
current: fooP,
|
||||||
|
previous: barP,
|
||||||
|
expectCurrent: fooP,
|
||||||
|
expectPrev: barP,
|
||||||
|
expectState: MovedState,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PrefixMoved",
|
||||||
|
current: fooP,
|
||||||
|
previous: preP,
|
||||||
|
expectCurrent: fooP,
|
||||||
|
expectPrev: preP,
|
||||||
|
expectState: MovedState,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "New",
|
||||||
|
current: fooP,
|
||||||
|
expectCurrent: fooP,
|
||||||
|
expectState: NewState,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Deleted",
|
||||||
|
previous: fooP,
|
||||||
|
expectPrev: fooP,
|
||||||
|
expectState: DeletedState,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range table {
|
||||||
|
suite.Run(test.name, func() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
b := NewBaseCollection(
|
||||||
|
test.current,
|
||||||
|
test.previous,
|
||||||
|
loc,
|
||||||
|
control.Options{},
|
||||||
|
test.doNotMerge)
|
||||||
|
|
||||||
|
assert.Equal(t, test.expectCurrent, b.FullPath(), "full path")
|
||||||
|
assert.Equal(t, test.expectPrev, b.PreviousPath(), "previous path")
|
||||||
|
assert.Equal(t, loc, b.LocationPath(), "location path")
|
||||||
|
assert.Equal(t, test.expectState, b.State(), "state")
|
||||||
|
assert.Equal(t, test.expectDoNotMerge, b.DoNotMergeItems(), "do not merge")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,3 +52,76 @@ func StateOf(prev, curr path.Path) CollectionState {
|
|||||||
|
|
||||||
return NotMovedState
|
return NotMovedState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// BaseCollection
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func NewBaseCollection(
|
||||||
|
curr, prev path.Path,
|
||||||
|
location *path.Builder,
|
||||||
|
ctrlOpts control.Options,
|
||||||
|
doNotMergeItems bool,
|
||||||
|
) BaseCollection {
|
||||||
|
return BaseCollection{
|
||||||
|
opts: ctrlOpts,
|
||||||
|
doNotMergeItems: doNotMergeItems,
|
||||||
|
fullPath: curr,
|
||||||
|
locationPath: location,
|
||||||
|
prevPath: prev,
|
||||||
|
state: StateOf(prev, curr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BaseCollection contains basic functionality like returning path, location,
|
||||||
|
// and state information. It can be embedded in other implementations to provide
|
||||||
|
// this functionality.
|
||||||
|
//
|
||||||
|
// Functionality like how items are fetched is left to the embedding struct.
|
||||||
|
type BaseCollection struct {
|
||||||
|
opts 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 CollectionState
|
||||||
|
|
||||||
|
// doNotMergeItems should only be true if the old delta token expired.
|
||||||
|
doNotMergeItems bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullPath returns the BaseCollection's fullPath []string
|
||||||
|
func (col *BaseCollection) FullPath() path.Path {
|
||||||
|
return col.fullPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocationPath produces the BaseCollection's full path, but with display names
|
||||||
|
// instead of IDs in the folders. Only populated for Calendars.
|
||||||
|
func (col *BaseCollection) LocationPath() *path.Builder {
|
||||||
|
return col.locationPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (col BaseCollection) PreviousPath() path.Path {
|
||||||
|
return col.prevPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func (col BaseCollection) State() CollectionState {
|
||||||
|
return col.state
|
||||||
|
}
|
||||||
|
|
||||||
|
func (col BaseCollection) DoNotMergeItems() bool {
|
||||||
|
return col.doNotMergeItems
|
||||||
|
}
|
||||||
|
|
||||||
|
func (col BaseCollection) Opts() control.Options {
|
||||||
|
return col.opts
|
||||||
|
}
|
||||||
|
|||||||
@ -189,7 +189,7 @@ func populateCollections(
|
|||||||
}
|
}
|
||||||
|
|
||||||
edc := NewCollection(
|
edc := NewCollection(
|
||||||
NewBaseCollection(
|
data.NewBaseCollection(
|
||||||
currPath,
|
currPath,
|
||||||
prevPath,
|
prevPath,
|
||||||
locPath,
|
locPath,
|
||||||
@ -242,7 +242,7 @@ func populateCollections(
|
|||||||
}
|
}
|
||||||
|
|
||||||
edc := NewCollection(
|
edc := NewCollection(
|
||||||
NewBaseCollection(
|
data.NewBaseCollection(
|
||||||
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
|
||||||
|
|||||||
@ -20,7 +20,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"
|
||||||
@ -38,71 +37,6 @@ const (
|
|||||||
numberOfRetries = 4
|
numberOfRetries = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewBaseCollection(
|
|
||||||
curr, prev path.Path,
|
|
||||||
location *path.Builder,
|
|
||||||
ctrlOpts control.Options,
|
|
||||||
doNotMergeItems bool,
|
|
||||||
) baseCollection {
|
|
||||||
return baseCollection{
|
|
||||||
ctrl: ctrlOpts,
|
|
||||||
doNotMergeItems: doNotMergeItems,
|
|
||||||
fullPath: curr,
|
|
||||||
locationPath: location,
|
|
||||||
prevPath: prev,
|
|
||||||
state: data.StateOf(prev, curr),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// baseCollection contains basic functionality like returning path, location,
|
|
||||||
// and state information. It can be embedded in other implementations to provide
|
|
||||||
// this functionality.
|
|
||||||
//
|
|
||||||
// Functionality like how items are fetched is left to the embedding struct.
|
|
||||||
type baseCollection struct {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// FullPath returns the baseCollection's fullPath []string
|
|
||||||
func (col *baseCollection) FullPath() path.Path {
|
|
||||||
return col.fullPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocationPath produces the baseCollection's full path, but with display names
|
|
||||||
// instead of IDs in the folders. Only populated for Calendars.
|
|
||||||
func (col *baseCollection) LocationPath() *path.Builder {
|
|
||||||
return col.locationPath
|
|
||||||
}
|
|
||||||
|
|
||||||
func (col baseCollection) PreviousPath() path.Path {
|
|
||||||
return col.prevPath
|
|
||||||
}
|
|
||||||
|
|
||||||
func (col baseCollection) State() data.CollectionState {
|
|
||||||
return col.state
|
|
||||||
}
|
|
||||||
|
|
||||||
func (col baseCollection) DoNotMergeItems() bool {
|
|
||||||
return col.doNotMergeItems
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateStatus is a utility function used to send the status update through
|
// updateStatus is a utility function used to send the status update through
|
||||||
// the channel.
|
// the channel.
|
||||||
func updateStatus(
|
func updateStatus(
|
||||||
@ -173,7 +107,7 @@ func getItemAndInfo(
|
|||||||
// 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(
|
||||||
bc baseCollection,
|
bc data.BaseCollection,
|
||||||
user string,
|
user string,
|
||||||
items itemGetterSerializer,
|
items itemGetterSerializer,
|
||||||
origAdded map[string]time.Time,
|
origAdded map[string]time.Time,
|
||||||
@ -199,7 +133,7 @@ func NewCollection(
|
|||||||
|
|
||||||
if !validModTimes {
|
if !validModTimes {
|
||||||
return &prefetchCollection{
|
return &prefetchCollection{
|
||||||
baseCollection: bc,
|
BaseCollection: bc,
|
||||||
user: user,
|
user: user,
|
||||||
added: added,
|
added: added,
|
||||||
removed: removed,
|
removed: removed,
|
||||||
@ -209,7 +143,7 @@ func NewCollection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &lazyFetchCollection{
|
return &lazyFetchCollection{
|
||||||
baseCollection: bc,
|
BaseCollection: bc,
|
||||||
user: user,
|
user: user,
|
||||||
added: added,
|
added: added,
|
||||||
removed: removed,
|
removed: removed,
|
||||||
@ -221,7 +155,7 @@ func NewCollection(
|
|||||||
// prefetchCollection implements the interface from data.BackupCollection
|
// prefetchCollection implements the interface from data.BackupCollection
|
||||||
// Structure holds data for an Exchange application for a single user
|
// Structure holds data for an Exchange application for a single user
|
||||||
type prefetchCollection struct {
|
type prefetchCollection struct {
|
||||||
baseCollection
|
data.BaseCollection
|
||||||
|
|
||||||
user string
|
user string
|
||||||
|
|
||||||
@ -283,7 +217,7 @@ func (col *prefetchCollection) streamItems(
|
|||||||
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
|
||||||
@ -331,7 +265,7 @@ func (col *prefetchCollection) streamItems(
|
|||||||
col.getter,
|
col.getter,
|
||||||
user,
|
user,
|
||||||
id,
|
id,
|
||||||
col.ctrl.ToggleFeatures.ExchangeImmutableIDs,
|
col.Opts().ToggleFeatures.ExchangeImmutableIDs,
|
||||||
parentPath)
|
parentPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't report errors for deleted items as there's no way for us to
|
// Don't report errors for deleted items as there's no way for us to
|
||||||
@ -380,7 +314,7 @@ func (col *prefetchCollection) streamItems(
|
|||||||
// information (path and mod time) is handed to kopia. Total bytes across all
|
// information (path and mod time) is handed to kopia. Total bytes across all
|
||||||
// items is not tracked.
|
// items is not tracked.
|
||||||
type lazyFetchCollection struct {
|
type lazyFetchCollection struct {
|
||||||
baseCollection
|
data.BaseCollection
|
||||||
|
|
||||||
user string
|
user string
|
||||||
|
|
||||||
@ -474,7 +408,7 @@ func (col *lazyFetchCollection) streamItems(
|
|||||||
id: id,
|
id: id,
|
||||||
getter: col.getter,
|
getter: col.getter,
|
||||||
modTime: modTime,
|
modTime: modTime,
|
||||||
immutableIDs: col.ctrl.ToggleFeatures.ExchangeImmutableIDs,
|
immutableIDs: col.Opts().ToggleFeatures.ExchangeImmutableIDs,
|
||||||
parentPath: parentPath,
|
parentPath: parentPath,
|
||||||
errs: errs,
|
errs: errs,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,32 +63,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"
|
|
||||||
user := "a-user"
|
|
||||||
folder := "a-folder"
|
|
||||||
name := "User"
|
|
||||||
|
|
||||||
fullPath, err := path.Build(
|
|
||||||
tenant,
|
|
||||||
user,
|
|
||||||
path.ExchangeService,
|
|
||||||
path.EmailCategory,
|
|
||||||
false,
|
|
||||||
folder)
|
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
|
||||||
|
|
||||||
edc := prefetchCollection{
|
|
||||||
baseCollection: baseCollection{
|
|
||||||
fullPath: fullPath,
|
|
||||||
},
|
|
||||||
user: name,
|
|
||||||
}
|
|
||||||
assert.Equal(t, name, edc.user)
|
|
||||||
assert.Equal(t, fullPath, edc.FullPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *CollectionUnitSuite) TestNewCollection_state() {
|
func (suite *CollectionUnitSuite) TestNewCollection_state() {
|
||||||
type collectionTypes struct {
|
type collectionTypes struct {
|
||||||
name string
|
name string
|
||||||
@ -153,7 +127,7 @@ func (suite *CollectionUnitSuite) TestNewCollection_state() {
|
|||||||
t := suite.T()
|
t := suite.T()
|
||||||
|
|
||||||
c := NewCollection(
|
c := NewCollection(
|
||||||
NewBaseCollection(
|
data.NewBaseCollection(
|
||||||
test.curr,
|
test.curr,
|
||||||
test.prev,
|
test.prev,
|
||||||
test.loc,
|
test.loc,
|
||||||
@ -296,7 +270,7 @@ func (suite *CollectionUnitSuite) TestPrefetchCollection_Items() {
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
col := NewCollection(
|
col := NewCollection(
|
||||||
NewBaseCollection(
|
data.NewBaseCollection(
|
||||||
fullPath,
|
fullPath,
|
||||||
nil,
|
nil,
|
||||||
locPath.ToBuilder(),
|
locPath.ToBuilder(),
|
||||||
@ -434,7 +408,7 @@ func (suite *CollectionUnitSuite) TestLazyFetchCollection_Items_LazyFetch() {
|
|||||||
defer mlg.check(t, test.expectReads)
|
defer mlg.check(t, test.expectReads)
|
||||||
|
|
||||||
col := NewCollection(
|
col := NewCollection(
|
||||||
NewBaseCollection(
|
data.NewBaseCollection(
|
||||||
fullPath,
|
fullPath,
|
||||||
nil,
|
nil,
|
||||||
locPath.ToBuilder(),
|
locPath.ToBuilder(),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user