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:
ashmrtn 2023-09-20 15:06:33 -07:00 committed by GitHub
parent c1ec3c6648
commit f767b67eca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 169 additions and 105 deletions

View File

@ -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")
})
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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,
} }

View File

@ -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(),