Create folder struct for backup details (#869)

## Description

<!-- Insert PR description-->
Folder entries allow recording the directory hierarchy of a backup in backup details for other consumers.

Although folders are present in the backup details and they have the logic to be displayed, they are not expected to be shown to users (later PRs will ensure this).

## 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. -->
* closes #860 

## Test Plan

<!-- How will this be tested prior to merging.-->
- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
ashmrtn 2022-09-15 17:17:28 -07:00 committed by GitHub
parent 87014a132b
commit ad2d046d19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 117 additions and 1 deletions

View File

@ -11,6 +11,12 @@ import (
"github.com/alcionai/corso/src/internal/model" "github.com/alcionai/corso/src/internal/model"
) )
type FolderEntry struct {
RepoRef string
ShortRef string
Info ItemInfo
}
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
// Model // Model
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
@ -83,7 +89,8 @@ type Details struct {
DetailsModel DetailsModel
// internal // internal
mu sync.Mutex `json:"-"` mu sync.Mutex `json:"-"`
knownFolders map[string]struct{} `json:"-"`
} }
func (d *Details) Add(repoRef, shortRef string, info ItemInfo) { func (d *Details) Add(repoRef, shortRef string, info ItemInfo) {
@ -96,6 +103,31 @@ func (d *Details) Add(repoRef, shortRef string, info ItemInfo) {
}) })
} }
// AddFolders adds entries for the given folders. It skips adding entries that
// have been added by previous calls.
func (d *Details) AddFolders(folders []FolderEntry) {
d.mu.Lock()
defer d.mu.Unlock()
if d.knownFolders == nil {
d.knownFolders = map[string]struct{}{}
}
for _, folder := range folders {
if _, ok := d.knownFolders[folder.ShortRef]; ok {
// Entry already exists, nothing to do.
continue
}
d.knownFolders[folder.ShortRef] = struct{}{}
d.Entries = append(d.Entries, DetailsEntry{
RepoRef: folder.RepoRef,
ShortRef: folder.ShortRef,
ItemInfo: folder.Info,
})
}
}
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
// Entry // Entry
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
@ -127,6 +159,10 @@ func (de DetailsEntry) MinimumPrintable() any {
func (de DetailsEntry) Headers() []string { func (de DetailsEntry) Headers() []string {
hs := []string{"Reference"} hs := []string{"Reference"}
if de.ItemInfo.Folder != nil {
hs = append(hs, de.ItemInfo.Folder.Headers()...)
}
if de.ItemInfo.Exchange != nil { if de.ItemInfo.Exchange != nil {
hs = append(hs, de.ItemInfo.Exchange.Headers()...) hs = append(hs, de.ItemInfo.Exchange.Headers()...)
} }
@ -146,6 +182,10 @@ func (de DetailsEntry) Headers() []string {
func (de DetailsEntry) Values() []string { func (de DetailsEntry) Values() []string {
vs := []string{de.ShortRef} vs := []string{de.ShortRef}
if de.ItemInfo.Folder != nil {
vs = append(vs, de.ItemInfo.Folder.Values()...)
}
if de.ItemInfo.Exchange != nil { if de.ItemInfo.Exchange != nil {
vs = append(vs, de.ItemInfo.Exchange.Values()...) vs = append(vs, de.ItemInfo.Exchange.Values()...)
} }
@ -174,11 +214,14 @@ const (
SharepointItem itemType = iota + 100 SharepointItem itemType = iota + 100
OneDriveItem itemType = iota + 200 OneDriveItem itemType = iota + 200
FolderItem itemType = iota + 300
) )
// ItemInfo is a oneOf that contains service specific // ItemInfo is a oneOf that contains service specific
// information about the item it tracks // information about the item it tracks
type ItemInfo struct { type ItemInfo struct {
Folder *FolderInfo `json:"folder,omitempty"`
Exchange *ExchangeInfo `json:"exchange,omitempty"` Exchange *ExchangeInfo `json:"exchange,omitempty"`
Sharepoint *SharepointInfo `json:"sharepoint,omitempty"` Sharepoint *SharepointInfo `json:"sharepoint,omitempty"`
OneDrive *OneDriveInfo `json:"oneDrive,omitempty"` OneDrive *OneDriveInfo `json:"oneDrive,omitempty"`
@ -192,6 +235,9 @@ type ItemInfo struct {
// calendar event). // calendar event).
func (i ItemInfo) infoType() itemType { func (i ItemInfo) infoType() itemType {
switch { switch {
case i.Folder != nil:
return i.Folder.ItemType
case i.Exchange != nil: case i.Exchange != nil:
return i.Exchange.ItemType return i.Exchange.ItemType
@ -205,6 +251,19 @@ func (i ItemInfo) infoType() itemType {
return UnknownType return UnknownType
} }
type FolderInfo struct {
ItemType itemType
DisplayName string `json:"displayName"`
}
func (i FolderInfo) Headers() []string {
return []string{"Display Name"}
}
func (i FolderInfo) Values() []string {
return []string{i.DisplayName}
}
// ExchangeInfo describes an exchange item // ExchangeInfo describes an exchange item
type ExchangeInfo struct { type ExchangeInfo struct {
ItemType itemType ItemType itemType

View File

@ -170,3 +170,60 @@ func (suite *DetailsUnitSuite) TestDetailsModel_Path() {
}) })
} }
} }
func (suite *DetailsUnitSuite) TestDetails_AddFolders() {
table := []struct {
name string
folders []details.FolderEntry
expectedShortRefs []string
}{
{
name: "MultipleFolders",
folders: []details.FolderEntry{
{
RepoRef: "rr1",
ShortRef: "sr1",
},
{
RepoRef: "rr2",
ShortRef: "sr2",
},
},
expectedShortRefs: []string{"sr1", "sr2"},
},
{
name: "MultipleFoldersWithRepeats",
folders: []details.FolderEntry{
{
RepoRef: "rr1",
ShortRef: "sr1",
},
{
RepoRef: "rr2",
ShortRef: "sr2",
},
{
RepoRef: "rr1",
ShortRef: "sr1",
},
{
RepoRef: "rr3",
ShortRef: "sr3",
},
},
expectedShortRefs: []string{"sr1", "sr2", "sr3"},
},
}
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
deets := details.Details{}
deets.AddFolders(test.folders)
assert.Len(t, deets.Entries, len(test.expectedShortRefs))
for _, e := range deets.Entries {
assert.Contains(t, test.expectedShortRefs, e.ShortRef)
}
})
}
}