Mark folder updated when an updated item is added (#1987)
## Description If an item is updated, update the folder entries it belongs to. Also contains a minor refactor - unexport `FolderEntry` to `folderEntry` ## Does this PR need a docs update or release note? - [x] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [ ] ⛔ No ## Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🐹 Trivial/Minor ## Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> * #1812 ## Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
5fec5ccd11
commit
ad691148fe
@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Folder entries in backup details now indicate whether an item in the hierarchy was updated
|
||||||
- Incremental backup support for Exchange ([#1777](https://github.com/alcionai/corso/issues/1777)). This is currently enabled by specifying the `--enable-incrementals`
|
- Incremental backup support for Exchange ([#1777](https://github.com/alcionai/corso/issues/1777)). This is currently enabled by specifying the `--enable-incrementals`
|
||||||
with the `backup create` command. This functionality will be enabled by default in an upcoming release.
|
with the `backup create` command. This functionality will be enabled by default in an upcoming release.
|
||||||
- Folder entries in backup details now include size and modified time for the hierarchy ([#1896](https://github.com/alcionai/corso/issues/1896))
|
- Folder entries in backup details now include size and modified time for the hierarchy ([#1896](https://github.com/alcionai/corso/issues/1896))
|
||||||
|
|||||||
@ -184,7 +184,11 @@ func (cp *corsoProgress) FinishedFile(relativePath string, err error) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
folders := details.FolderEntriesForPath(parent)
|
folders := details.FolderEntriesForPath(parent)
|
||||||
cp.deets.AddFoldersForItem(folders, *d.info)
|
cp.deets.AddFoldersForItem(
|
||||||
|
folders,
|
||||||
|
*d.info,
|
||||||
|
true, // itemUpdated = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kopia interface function used as a callback when kopia finishes hashing a file.
|
// Kopia interface function used as a callback when kopia finishes hashing a file.
|
||||||
|
|||||||
@ -515,18 +515,20 @@ func mergeDetails(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(ashmrtn): This may need updated if we start using this merge
|
||||||
|
// strategry for items that were cached in kopia.
|
||||||
|
itemUpdated := newPath.String() != rr.String()
|
||||||
|
|
||||||
deets.Add(
|
deets.Add(
|
||||||
newPath.String(),
|
newPath.String(),
|
||||||
newPath.ShortRef(),
|
newPath.ShortRef(),
|
||||||
newPath.ToBuilder().Dir().ShortRef(),
|
newPath.ToBuilder().Dir().ShortRef(),
|
||||||
// TODO(ashmrtn): This may need updated if we start using this merge
|
itemUpdated,
|
||||||
// strategry for items that were cached in kopia.
|
|
||||||
newPath.String() != rr.String(),
|
|
||||||
item,
|
item,
|
||||||
)
|
)
|
||||||
|
|
||||||
folders := details.FolderEntriesForPath(newPath.ToBuilder().Dir())
|
folders := details.FolderEntriesForPath(newPath.ToBuilder().Dir())
|
||||||
deets.AddFoldersForItem(folders, item)
|
deets.AddFoldersForItem(folders, item, itemUpdated)
|
||||||
|
|
||||||
// Track how many entries we added so that we know if we got them all when
|
// Track how many entries we added so that we know if we got them all when
|
||||||
// we're done.
|
// we're done.
|
||||||
|
|||||||
@ -14,10 +14,11 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FolderEntry struct {
|
type folderEntry struct {
|
||||||
RepoRef string
|
RepoRef string
|
||||||
ShortRef string
|
ShortRef string
|
||||||
ParentRef string
|
ParentRef string
|
||||||
|
Updated bool
|
||||||
Info ItemInfo
|
Info ItemInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +107,7 @@ func (dm DetailsModel) Items() []*DetailsEntry {
|
|||||||
type Builder struct {
|
type Builder struct {
|
||||||
d Details
|
d Details
|
||||||
mu sync.Mutex `json:"-"`
|
mu sync.Mutex `json:"-"`
|
||||||
knownFolders map[string]FolderEntry `json:"-"`
|
knownFolders map[string]folderEntry `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) Add(repoRef, shortRef, parentRef string, updated bool, info ItemInfo) {
|
func (b *Builder) Add(repoRef, shortRef, parentRef string, updated bool, info ItemInfo) {
|
||||||
@ -130,13 +131,13 @@ func (b *Builder) Details() *Details {
|
|||||||
// TODO(ashmrtn): If we never need to pre-populate the modified time of a folder
|
// TODO(ashmrtn): If we never need to pre-populate the modified time of a folder
|
||||||
// we should just merge this with AddFoldersForItem, have Add call
|
// we should just merge this with AddFoldersForItem, have Add call
|
||||||
// AddFoldersForItem, and unexport AddFoldersForItem.
|
// AddFoldersForItem, and unexport AddFoldersForItem.
|
||||||
func FolderEntriesForPath(parent *path.Builder) []FolderEntry {
|
func FolderEntriesForPath(parent *path.Builder) []folderEntry {
|
||||||
folders := []FolderEntry{}
|
folders := []folderEntry{}
|
||||||
|
|
||||||
for len(parent.Elements()) > 0 {
|
for len(parent.Elements()) > 0 {
|
||||||
nextParent := parent.Dir()
|
nextParent := parent.Dir()
|
||||||
|
|
||||||
folders = append(folders, FolderEntry{
|
folders = append(folders, folderEntry{
|
||||||
RepoRef: parent.String(),
|
RepoRef: parent.String(),
|
||||||
ShortRef: parent.ShortRef(),
|
ShortRef: parent.ShortRef(),
|
||||||
ParentRef: nextParent.ShortRef(),
|
ParentRef: nextParent.ShortRef(),
|
||||||
@ -156,12 +157,12 @@ func FolderEntriesForPath(parent *path.Builder) []FolderEntry {
|
|||||||
|
|
||||||
// AddFoldersForItem adds entries for the given folders. It skips adding entries that
|
// AddFoldersForItem adds entries for the given folders. It skips adding entries that
|
||||||
// have been added by previous calls.
|
// have been added by previous calls.
|
||||||
func (b *Builder) AddFoldersForItem(folders []FolderEntry, itemInfo ItemInfo) {
|
func (b *Builder) AddFoldersForItem(folders []folderEntry, itemInfo ItemInfo, updated bool) {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
if b.knownFolders == nil {
|
if b.knownFolders == nil {
|
||||||
b.knownFolders = map[string]FolderEntry{}
|
b.knownFolders = map[string]folderEntry{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, folder := range folders {
|
for _, folder := range folders {
|
||||||
@ -180,6 +181,12 @@ func (b *Builder) AddFoldersForItem(folders []FolderEntry, itemInfo ItemInfo) {
|
|||||||
folder.Info.Folder.Modified = itemModified
|
folder.Info.Folder.Modified = itemModified
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the item being added was "updated" - propagate that to the
|
||||||
|
// folder entries
|
||||||
|
if updated {
|
||||||
|
folder.Updated = true
|
||||||
|
}
|
||||||
|
|
||||||
b.knownFolders[folder.ShortRef] = folder
|
b.knownFolders[folder.ShortRef] = folder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,12 +213,13 @@ func (d *Details) add(repoRef, shortRef, parentRef string, updated bool, info It
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addFolder adds an entry for the given folder.
|
// addFolder adds an entry for the given folder.
|
||||||
func (d *Details) addFolder(folder FolderEntry) {
|
func (d *Details) addFolder(folder folderEntry) {
|
||||||
d.Entries = append(d.Entries, DetailsEntry{
|
d.Entries = append(d.Entries, DetailsEntry{
|
||||||
RepoRef: folder.RepoRef,
|
RepoRef: folder.RepoRef,
|
||||||
ShortRef: folder.ShortRef,
|
ShortRef: folder.ShortRef,
|
||||||
ParentRef: folder.ParentRef,
|
ParentRef: folder.ParentRef,
|
||||||
ItemInfo: folder.Info,
|
ItemInfo: folder.Info,
|
||||||
|
Updated: folder.Updated,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package details_test
|
package details
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/common"
|
"github.com/alcionai/corso/src/internal/common"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,13 +32,13 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
|
|||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
entry details.DetailsEntry
|
entry DetailsEntry
|
||||||
expectHs []string
|
expectHs []string
|
||||||
expectVs []string
|
expectVs []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no info",
|
name: "no info",
|
||||||
entry: details.DetailsEntry{
|
entry: DetailsEntry{
|
||||||
RepoRef: "reporef",
|
RepoRef: "reporef",
|
||||||
ShortRef: "deadbeef",
|
ShortRef: "deadbeef",
|
||||||
},
|
},
|
||||||
@ -48,12 +47,12 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "exchange event info",
|
name: "exchange event info",
|
||||||
entry: details.DetailsEntry{
|
entry: DetailsEntry{
|
||||||
RepoRef: "reporef",
|
RepoRef: "reporef",
|
||||||
ShortRef: "deadbeef",
|
ShortRef: "deadbeef",
|
||||||
ItemInfo: details.ItemInfo{
|
ItemInfo: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
ItemType: details.ExchangeEvent,
|
ItemType: ExchangeEvent,
|
||||||
EventStart: now,
|
EventStart: now,
|
||||||
EventEnd: now,
|
EventEnd: now,
|
||||||
Organizer: "organizer",
|
Organizer: "organizer",
|
||||||
@ -67,12 +66,12 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "exchange contact info",
|
name: "exchange contact info",
|
||||||
entry: details.DetailsEntry{
|
entry: DetailsEntry{
|
||||||
RepoRef: "reporef",
|
RepoRef: "reporef",
|
||||||
ShortRef: "deadbeef",
|
ShortRef: "deadbeef",
|
||||||
ItemInfo: details.ItemInfo{
|
ItemInfo: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
ItemType: details.ExchangeContact,
|
ItemType: ExchangeContact,
|
||||||
ContactName: "contactName",
|
ContactName: "contactName",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -82,12 +81,12 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "exchange mail info",
|
name: "exchange mail info",
|
||||||
entry: details.DetailsEntry{
|
entry: DetailsEntry{
|
||||||
RepoRef: "reporef",
|
RepoRef: "reporef",
|
||||||
ShortRef: "deadbeef",
|
ShortRef: "deadbeef",
|
||||||
ItemInfo: details.ItemInfo{
|
ItemInfo: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
ItemType: details.ExchangeMail,
|
ItemType: ExchangeMail,
|
||||||
Sender: "sender",
|
Sender: "sender",
|
||||||
Subject: "subject",
|
Subject: "subject",
|
||||||
Received: now,
|
Received: now,
|
||||||
@ -99,11 +98,11 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "sharepoint info",
|
name: "sharepoint info",
|
||||||
entry: details.DetailsEntry{
|
entry: DetailsEntry{
|
||||||
RepoRef: "reporef",
|
RepoRef: "reporef",
|
||||||
ShortRef: "deadbeef",
|
ShortRef: "deadbeef",
|
||||||
ItemInfo: details.ItemInfo{
|
ItemInfo: ItemInfo{
|
||||||
SharePoint: &details.SharePointInfo{
|
SharePoint: &SharePointInfo{
|
||||||
ItemName: "itemName",
|
ItemName: "itemName",
|
||||||
ParentPath: "parentPath",
|
ParentPath: "parentPath",
|
||||||
Size: 1000,
|
Size: 1000,
|
||||||
@ -118,11 +117,11 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "oneDrive info",
|
name: "oneDrive info",
|
||||||
entry: details.DetailsEntry{
|
entry: DetailsEntry{
|
||||||
RepoRef: "reporef",
|
RepoRef: "reporef",
|
||||||
ShortRef: "deadbeef",
|
ShortRef: "deadbeef",
|
||||||
ItemInfo: details.ItemInfo{
|
ItemInfo: ItemInfo{
|
||||||
OneDrive: &details.OneDriveInfo{
|
OneDrive: &OneDriveInfo{
|
||||||
ItemName: "itemName",
|
ItemName: "itemName",
|
||||||
ParentPath: "parentPath",
|
ParentPath: "parentPath",
|
||||||
Size: 1000,
|
Size: 1000,
|
||||||
@ -149,7 +148,7 @@ func (suite *DetailsUnitSuite) TestDetailsEntry_HeadersValues() {
|
|||||||
|
|
||||||
var pathItemsTable = []struct {
|
var pathItemsTable = []struct {
|
||||||
name string
|
name string
|
||||||
ents []details.DetailsEntry
|
ents []DetailsEntry
|
||||||
expectRefs []string
|
expectRefs []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -159,14 +158,14 @@ var pathItemsTable = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "single entry",
|
name: "single entry",
|
||||||
ents: []details.DetailsEntry{
|
ents: []DetailsEntry{
|
||||||
{RepoRef: "abcde"},
|
{RepoRef: "abcde"},
|
||||||
},
|
},
|
||||||
expectRefs: []string{"abcde"},
|
expectRefs: []string{"abcde"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple entries",
|
name: "multiple entries",
|
||||||
ents: []details.DetailsEntry{
|
ents: []DetailsEntry{
|
||||||
{RepoRef: "abcde"},
|
{RepoRef: "abcde"},
|
||||||
{RepoRef: "12345"},
|
{RepoRef: "12345"},
|
||||||
},
|
},
|
||||||
@ -174,13 +173,13 @@ var pathItemsTable = []struct {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple entries with folder",
|
name: "multiple entries with folder",
|
||||||
ents: []details.DetailsEntry{
|
ents: []DetailsEntry{
|
||||||
{RepoRef: "abcde"},
|
{RepoRef: "abcde"},
|
||||||
{RepoRef: "12345"},
|
{RepoRef: "12345"},
|
||||||
{
|
{
|
||||||
RepoRef: "deadbeef",
|
RepoRef: "deadbeef",
|
||||||
ItemInfo: details.ItemInfo{
|
ItemInfo: ItemInfo{
|
||||||
Folder: &details.FolderInfo{
|
Folder: &FolderInfo{
|
||||||
DisplayName: "test folder",
|
DisplayName: "test folder",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -193,8 +192,8 @@ var pathItemsTable = []struct {
|
|||||||
func (suite *DetailsUnitSuite) TestDetailsModel_Path() {
|
func (suite *DetailsUnitSuite) TestDetailsModel_Path() {
|
||||||
for _, test := range pathItemsTable {
|
for _, test := range pathItemsTable {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
d := details.Details{
|
d := Details{
|
||||||
DetailsModel: details.DetailsModel{
|
DetailsModel: DetailsModel{
|
||||||
Entries: test.ents,
|
Entries: test.ents,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -206,8 +205,8 @@ func (suite *DetailsUnitSuite) TestDetailsModel_Path() {
|
|||||||
func (suite *DetailsUnitSuite) TestDetailsModel_Items() {
|
func (suite *DetailsUnitSuite) TestDetailsModel_Items() {
|
||||||
for _, test := range pathItemsTable {
|
for _, test := range pathItemsTable {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
d := details.Details{
|
d := Details{
|
||||||
DetailsModel: details.DetailsModel{
|
DetailsModel: DetailsModel{
|
||||||
Entries: test.ents,
|
Entries: test.ents,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -227,8 +226,8 @@ func (suite *DetailsUnitSuite) TestDetails_AddFolders() {
|
|||||||
folderTimeOlderThanItem := time.Date(2022, 9, 21, 10, 0, 0, 0, time.UTC)
|
folderTimeOlderThanItem := time.Date(2022, 9, 21, 10, 0, 0, 0, time.UTC)
|
||||||
folderTimeNewerThanItem := time.Date(2022, 11, 21, 10, 0, 0, 0, time.UTC)
|
folderTimeNewerThanItem := time.Date(2022, 11, 21, 10, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
itemInfo := details.ItemInfo{
|
itemInfo := ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
Size: 20,
|
Size: 20,
|
||||||
Modified: itemTime,
|
Modified: itemTime,
|
||||||
},
|
},
|
||||||
@ -236,19 +235,19 @@ func (suite *DetailsUnitSuite) TestDetails_AddFolders() {
|
|||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
folders []details.FolderEntry
|
folders []folderEntry
|
||||||
expectedShortRefs []string
|
expectedShortRefs []string
|
||||||
expectedFolderInfo map[string]details.FolderInfo
|
expectedFolderInfo map[string]FolderInfo
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "MultipleFolders",
|
name: "MultipleFolders",
|
||||||
folders: []details.FolderEntry{
|
folders: []folderEntry{
|
||||||
{
|
{
|
||||||
RepoRef: "rr1",
|
RepoRef: "rr1",
|
||||||
ShortRef: "sr1",
|
ShortRef: "sr1",
|
||||||
ParentRef: "pr1",
|
ParentRef: "pr1",
|
||||||
Info: details.ItemInfo{
|
Info: ItemInfo{
|
||||||
Folder: &details.FolderInfo{
|
Folder: &FolderInfo{
|
||||||
Modified: folderTimeOlderThanItem,
|
Modified: folderTimeOlderThanItem,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -257,28 +256,28 @@ func (suite *DetailsUnitSuite) TestDetails_AddFolders() {
|
|||||||
RepoRef: "rr2",
|
RepoRef: "rr2",
|
||||||
ShortRef: "sr2",
|
ShortRef: "sr2",
|
||||||
ParentRef: "pr2",
|
ParentRef: "pr2",
|
||||||
Info: details.ItemInfo{
|
Info: ItemInfo{
|
||||||
Folder: &details.FolderInfo{
|
Folder: &FolderInfo{
|
||||||
Modified: folderTimeNewerThanItem,
|
Modified: folderTimeNewerThanItem,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedShortRefs: []string{"sr1", "sr2"},
|
expectedShortRefs: []string{"sr1", "sr2"},
|
||||||
expectedFolderInfo: map[string]details.FolderInfo{
|
expectedFolderInfo: map[string]FolderInfo{
|
||||||
"sr1": {Size: 20, Modified: itemTime},
|
"sr1": {Size: 20, Modified: itemTime},
|
||||||
"sr2": {Size: 20, Modified: folderTimeNewerThanItem},
|
"sr2": {Size: 20, Modified: folderTimeNewerThanItem},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MultipleFoldersWithRepeats",
|
name: "MultipleFoldersWithRepeats",
|
||||||
folders: []details.FolderEntry{
|
folders: []folderEntry{
|
||||||
{
|
{
|
||||||
RepoRef: "rr1",
|
RepoRef: "rr1",
|
||||||
ShortRef: "sr1",
|
ShortRef: "sr1",
|
||||||
ParentRef: "pr1",
|
ParentRef: "pr1",
|
||||||
Info: details.ItemInfo{
|
Info: ItemInfo{
|
||||||
Folder: &details.FolderInfo{
|
Folder: &FolderInfo{
|
||||||
Modified: folderTimeOlderThanItem,
|
Modified: folderTimeOlderThanItem,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -287,8 +286,8 @@ func (suite *DetailsUnitSuite) TestDetails_AddFolders() {
|
|||||||
RepoRef: "rr2",
|
RepoRef: "rr2",
|
||||||
ShortRef: "sr2",
|
ShortRef: "sr2",
|
||||||
ParentRef: "pr2",
|
ParentRef: "pr2",
|
||||||
Info: details.ItemInfo{
|
Info: ItemInfo{
|
||||||
Folder: &details.FolderInfo{
|
Folder: &FolderInfo{
|
||||||
Modified: folderTimeOlderThanItem,
|
Modified: folderTimeOlderThanItem,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -297,8 +296,8 @@ func (suite *DetailsUnitSuite) TestDetails_AddFolders() {
|
|||||||
RepoRef: "rr1",
|
RepoRef: "rr1",
|
||||||
ShortRef: "sr1",
|
ShortRef: "sr1",
|
||||||
ParentRef: "pr1",
|
ParentRef: "pr1",
|
||||||
Info: details.ItemInfo{
|
Info: ItemInfo{
|
||||||
Folder: &details.FolderInfo{
|
Folder: &FolderInfo{
|
||||||
Modified: folderTimeOlderThanItem,
|
Modified: folderTimeOlderThanItem,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -307,15 +306,15 @@ func (suite *DetailsUnitSuite) TestDetails_AddFolders() {
|
|||||||
RepoRef: "rr3",
|
RepoRef: "rr3",
|
||||||
ShortRef: "sr3",
|
ShortRef: "sr3",
|
||||||
ParentRef: "pr3",
|
ParentRef: "pr3",
|
||||||
Info: details.ItemInfo{
|
Info: ItemInfo{
|
||||||
Folder: &details.FolderInfo{
|
Folder: &FolderInfo{
|
||||||
Modified: folderTimeNewerThanItem,
|
Modified: folderTimeNewerThanItem,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedShortRefs: []string{"sr1", "sr2", "sr3"},
|
expectedShortRefs: []string{"sr1", "sr2", "sr3"},
|
||||||
expectedFolderInfo: map[string]details.FolderInfo{
|
expectedFolderInfo: map[string]FolderInfo{
|
||||||
// Two items were added
|
// Two items were added
|
||||||
"sr1": {Size: 40, Modified: itemTime},
|
"sr1": {Size: 40, Modified: itemTime},
|
||||||
"sr2": {Size: 20, Modified: itemTime},
|
"sr2": {Size: 20, Modified: itemTime},
|
||||||
@ -325,8 +324,8 @@ func (suite *DetailsUnitSuite) TestDetails_AddFolders() {
|
|||||||
}
|
}
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
builder := details.Builder{}
|
builder := Builder{}
|
||||||
builder.AddFoldersForItem(test.folders, itemInfo)
|
builder.AddFoldersForItem(test.folders, itemInfo, true)
|
||||||
deets := builder.Details()
|
deets := builder.Details()
|
||||||
assert.Len(t, deets.Entries, len(test.expectedShortRefs))
|
assert.Len(t, deets.Entries, len(test.expectedShortRefs))
|
||||||
|
|
||||||
@ -339,49 +338,132 @@ func (suite *DetailsUnitSuite) TestDetails_AddFolders() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *DetailsUnitSuite) TestDetails_AddFoldersUpdate() {
|
||||||
|
itemInfo := ItemInfo{
|
||||||
|
Exchange: &ExchangeInfo{},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
folders []folderEntry
|
||||||
|
itemUpdated bool
|
||||||
|
expectedFolderUpdatedValue map[string]bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "ItemNotUpdated_NoChange",
|
||||||
|
folders: []folderEntry{
|
||||||
|
{
|
||||||
|
RepoRef: "rr1",
|
||||||
|
ShortRef: "sr1",
|
||||||
|
ParentRef: "pr1",
|
||||||
|
Info: ItemInfo{
|
||||||
|
Folder: &FolderInfo{},
|
||||||
|
},
|
||||||
|
Updated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RepoRef: "rr2",
|
||||||
|
ShortRef: "sr2",
|
||||||
|
ParentRef: "pr2",
|
||||||
|
Info: ItemInfo{
|
||||||
|
Folder: &FolderInfo{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
itemUpdated: false,
|
||||||
|
expectedFolderUpdatedValue: map[string]bool{
|
||||||
|
"sr1": true,
|
||||||
|
"sr2": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ItemUpdated",
|
||||||
|
folders: []folderEntry{
|
||||||
|
{
|
||||||
|
RepoRef: "rr1",
|
||||||
|
ShortRef: "sr1",
|
||||||
|
ParentRef: "pr1",
|
||||||
|
Info: ItemInfo{
|
||||||
|
Folder: &FolderInfo{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RepoRef: "rr2",
|
||||||
|
ShortRef: "sr2",
|
||||||
|
ParentRef: "pr2",
|
||||||
|
Info: ItemInfo{
|
||||||
|
Folder: &FolderInfo{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
itemUpdated: true,
|
||||||
|
expectedFolderUpdatedValue: map[string]bool{
|
||||||
|
"sr1": true,
|
||||||
|
"sr2": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
|
builder := Builder{}
|
||||||
|
builder.AddFoldersForItem(test.folders, itemInfo, test.itemUpdated)
|
||||||
|
deets := builder.Details()
|
||||||
|
assert.Len(t, deets.Entries, len(test.expectedFolderUpdatedValue))
|
||||||
|
|
||||||
|
for _, e := range deets.Entries {
|
||||||
|
assert.Equalf(
|
||||||
|
t,
|
||||||
|
test.expectedFolderUpdatedValue[e.ShortRef],
|
||||||
|
e.Updated, "%s updated value incorrect",
|
||||||
|
e.ShortRef)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *DetailsUnitSuite) TestDetails_AddFoldersDifferentServices() {
|
func (suite *DetailsUnitSuite) TestDetails_AddFoldersDifferentServices() {
|
||||||
itemTime := time.Date(2022, 10, 21, 10, 0, 0, 0, time.UTC)
|
itemTime := time.Date(2022, 10, 21, 10, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
item details.ItemInfo
|
item ItemInfo
|
||||||
expectedFolderInfo details.FolderInfo
|
expectedFolderInfo FolderInfo
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Exchange",
|
name: "Exchange",
|
||||||
item: details.ItemInfo{
|
item: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
Size: 20,
|
Size: 20,
|
||||||
Modified: itemTime,
|
Modified: itemTime,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedFolderInfo: details.FolderInfo{
|
expectedFolderInfo: FolderInfo{
|
||||||
Size: 20,
|
Size: 20,
|
||||||
Modified: itemTime,
|
Modified: itemTime,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OneDrive",
|
name: "OneDrive",
|
||||||
item: details.ItemInfo{
|
item: ItemInfo{
|
||||||
OneDrive: &details.OneDriveInfo{
|
OneDrive: &OneDriveInfo{
|
||||||
Size: 20,
|
Size: 20,
|
||||||
Modified: itemTime,
|
Modified: itemTime,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedFolderInfo: details.FolderInfo{
|
expectedFolderInfo: FolderInfo{
|
||||||
Size: 20,
|
Size: 20,
|
||||||
Modified: itemTime,
|
Modified: itemTime,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SharePoint",
|
name: "SharePoint",
|
||||||
item: details.ItemInfo{
|
item: ItemInfo{
|
||||||
SharePoint: &details.SharePointInfo{
|
SharePoint: &SharePointInfo{
|
||||||
Size: 20,
|
Size: 20,
|
||||||
Modified: itemTime,
|
Modified: itemTime,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedFolderInfo: details.FolderInfo{
|
expectedFolderInfo: FolderInfo{
|
||||||
Size: 20,
|
Size: 20,
|
||||||
Modified: itemTime,
|
Modified: itemTime,
|
||||||
},
|
},
|
||||||
@ -389,17 +471,17 @@ func (suite *DetailsUnitSuite) TestDetails_AddFoldersDifferentServices() {
|
|||||||
}
|
}
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
folderEntry := details.FolderEntry{
|
folder := folderEntry{
|
||||||
RepoRef: "rr1",
|
RepoRef: "rr1",
|
||||||
ShortRef: "sr1",
|
ShortRef: "sr1",
|
||||||
ParentRef: "pr1",
|
ParentRef: "pr1",
|
||||||
Info: details.ItemInfo{
|
Info: ItemInfo{
|
||||||
Folder: &details.FolderInfo{},
|
Folder: &FolderInfo{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
builder := details.Builder{}
|
builder := Builder{}
|
||||||
builder.AddFoldersForItem([]details.FolderEntry{folderEntry}, test.item)
|
builder.AddFoldersForItem([]folderEntry{folder}, test.item, true)
|
||||||
deets := builder.Details()
|
deets := builder.Details()
|
||||||
require.Len(t, deets.Entries, 1)
|
require.Len(t, deets.Entries, 1)
|
||||||
|
|
||||||
@ -469,92 +551,92 @@ func (suite *DetailsUnitSuite) TestUpdateItem() {
|
|||||||
|
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
input details.ItemInfo
|
input ItemInfo
|
||||||
newPath path.Path
|
newPath path.Path
|
||||||
errCheck assert.ErrorAssertionFunc
|
errCheck assert.ErrorAssertionFunc
|
||||||
expectedItem details.ItemInfo
|
expectedItem ItemInfo
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "ExchangeEventNoChange",
|
name: "ExchangeEventNoChange",
|
||||||
input: details.ItemInfo{
|
input: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
ItemType: details.ExchangeEvent,
|
ItemType: ExchangeEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
expectedItem: details.ItemInfo{
|
expectedItem: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
ItemType: details.ExchangeEvent,
|
ItemType: ExchangeEvent,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ExchangeContactNoChange",
|
name: "ExchangeContactNoChange",
|
||||||
input: details.ItemInfo{
|
input: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
ItemType: details.ExchangeContact,
|
ItemType: ExchangeContact,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
expectedItem: details.ItemInfo{
|
expectedItem: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
ItemType: details.ExchangeContact,
|
ItemType: ExchangeContact,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ExchangeMailNoChange",
|
name: "ExchangeMailNoChange",
|
||||||
input: details.ItemInfo{
|
input: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
ItemType: details.ExchangeMail,
|
ItemType: ExchangeMail,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
expectedItem: details.ItemInfo{
|
expectedItem: ItemInfo{
|
||||||
Exchange: &details.ExchangeInfo{
|
Exchange: &ExchangeInfo{
|
||||||
ItemType: details.ExchangeMail,
|
ItemType: ExchangeMail,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OneDrive",
|
name: "OneDrive",
|
||||||
input: details.ItemInfo{
|
input: ItemInfo{
|
||||||
OneDrive: &details.OneDriveInfo{
|
OneDrive: &OneDriveInfo{
|
||||||
ItemType: details.OneDriveItem,
|
ItemType: OneDriveItem,
|
||||||
ParentPath: folder1,
|
ParentPath: folder1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
newPath: newOneDrivePath,
|
newPath: newOneDrivePath,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
expectedItem: details.ItemInfo{
|
expectedItem: ItemInfo{
|
||||||
OneDrive: &details.OneDriveInfo{
|
OneDrive: &OneDriveInfo{
|
||||||
ItemType: details.OneDriveItem,
|
ItemType: OneDriveItem,
|
||||||
ParentPath: folder2,
|
ParentPath: folder2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SharePoint",
|
name: "SharePoint",
|
||||||
input: details.ItemInfo{
|
input: ItemInfo{
|
||||||
SharePoint: &details.SharePointInfo{
|
SharePoint: &SharePointInfo{
|
||||||
ItemType: details.SharePointItem,
|
ItemType: SharePointItem,
|
||||||
ParentPath: folder1,
|
ParentPath: folder1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
newPath: newOneDrivePath,
|
newPath: newOneDrivePath,
|
||||||
errCheck: assert.NoError,
|
errCheck: assert.NoError,
|
||||||
expectedItem: details.ItemInfo{
|
expectedItem: ItemInfo{
|
||||||
SharePoint: &details.SharePointInfo{
|
SharePoint: &SharePointInfo{
|
||||||
ItemType: details.SharePointItem,
|
ItemType: SharePointItem,
|
||||||
ParentPath: folder2,
|
ParentPath: folder2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OneDriveBadPath",
|
name: "OneDriveBadPath",
|
||||||
input: details.ItemInfo{
|
input: ItemInfo{
|
||||||
OneDrive: &details.OneDriveInfo{
|
OneDrive: &OneDriveInfo{
|
||||||
ItemType: details.OneDriveItem,
|
ItemType: OneDriveItem,
|
||||||
ParentPath: folder1,
|
ParentPath: folder1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -563,9 +645,9 @@ func (suite *DetailsUnitSuite) TestUpdateItem() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SharePointBadPath",
|
name: "SharePointBadPath",
|
||||||
input: details.ItemInfo{
|
input: ItemInfo{
|
||||||
SharePoint: &details.SharePointInfo{
|
SharePoint: &SharePointInfo{
|
||||||
ItemType: details.SharePointItem,
|
ItemType: SharePointItem,
|
||||||
ParentPath: folder1,
|
ParentPath: folder1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -577,7 +659,7 @@ func (suite *DetailsUnitSuite) TestUpdateItem() {
|
|||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
item := test.input
|
item := test.input
|
||||||
err := details.UpdateItem(&item, test.newPath)
|
err := UpdateItem(&item, test.newPath)
|
||||||
test.errCheck(t, err)
|
test.errCheck(t, err)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user