Alternative way to handle 2-level calendars hierarchy (#2397)

## Description

All calendars except the default are nested under a "Other Calendars" folder. Having a non-default calendar named the same as the default calendar does not cause problems when fetching the default calendar by name. Only the default calendar will be returned in that situation.

This fixes the bug where we had multiple collections for the same path but representing different folders.

Also updates the restore execution path to handle the new nested folder structure.

Backup, incremental backup, and restore flows tested manually

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

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

## Issue(s)

* #2388

## Test Plan

- [x] 💪 Manual
- [ ]  Unit test
- [ ] 💚 E2E
This commit is contained in:
ashmrtn 2023-02-03 15:29:55 -08:00 committed by GitHub
parent 35d89427ce
commit 38f56cccba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 30 additions and 11 deletions

View File

@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `--restore-permissions` flag to toggle restoration of OneDrive permissions - Add `--restore-permissions` flag to toggle restoration of OneDrive permissions
- Add versions to backups so that we can understand/handle older backup formats - Add versions to backups so that we can understand/handle older backup formats
### Fixed
- Backing up a calendar that has the same name as the default calendar
### Known Issues ### Known Issues
- When the same user has permissions to a file and the containing - When the same user has permissions to a file and the containing

View File

@ -501,10 +501,11 @@ func (suite *FolderCacheIntegrationSuite) TestCreateContainerDestination() {
directoryCaches = make(map[path.CategoryType]graph.ContainerResolver) directoryCaches = make(map[path.CategoryType]graph.ContainerResolver)
folderName = tester.DefaultTestRestoreDestination().ContainerName folderName = tester.DefaultTestRestoreDestination().ContainerName
tests = []struct { tests = []struct {
name string name string
pathFunc1 func(t *testing.T) path.Path pathFunc1 func(t *testing.T) path.Path
pathFunc2 func(t *testing.T) path.Path pathFunc2 func(t *testing.T) path.Path
category path.CategoryType category path.CategoryType
folderPrefix string
}{ }{
{ {
name: "Mail Cache Test", name: "Mail Cache Test",
@ -587,6 +588,7 @@ func (suite *FolderCacheIntegrationSuite) TestCreateContainerDestination() {
require.NoError(t, err) require.NoError(t, err)
return aPath return aPath
}, },
folderPrefix: calendarOthersFolder,
}, },
} }
) )
@ -617,8 +619,9 @@ func (suite *FolderCacheIntegrationSuite) TestCreateContainerDestination() {
_, err = resolver.IDToPath(ctx, secondID) _, err = resolver.IDToPath(ctx, secondID)
require.NoError(t, err) require.NoError(t, err)
_, ok := resolver.PathInCache(folderName) p := stdpath.Join(test.folderPrefix, folderName)
require.True(t, ok) _, ok := resolver.PathInCache(p)
require.True(t, ok, "looking for path in cache: %s", p)
}) })
} }
} }

View File

@ -537,9 +537,9 @@ func (suite *DataCollectionsIntegrationSuite) TestEventsSerializationRegression(
}, },
{ {
name: "Birthday Calendar", name: "Birthday Calendar",
expected: "Birthdays", expected: calendarOthersFolder + "/Birthdays",
scope: selectors.NewExchangeBackup(users).EventCalendars( scope: selectors.NewExchangeBackup(users).EventCalendars(
[]string{"Birthdays"}, []string{calendarOthersFolder + "/Birthdays"},
selectors.PrefixMatch(), selectors.PrefixMatch(),
)[0], )[0],
}, },

View File

@ -64,7 +64,15 @@ func (ecc *eventCalendarCache) Populate(
return errors.Wrap(err, "initializing") return errors.Wrap(err, "initializing")
} }
err := ecc.enumer.EnumerateContainers(ctx, ecc.userID, "", ecc.addFolder) err := ecc.enumer.EnumerateContainers(
ctx,
ecc.userID,
"",
func(cf graph.CacheFolder) error {
cf.SetPath(path.Builder{}.Append(calendarOthersFolder, *cf.GetDisplayName()))
return ecc.addFolder(cf)
},
)
if err != nil { if err != nil {
return errors.Wrap(err, "enumerating containers") return errors.Wrap(err, "enumerating containers")
} }
@ -83,7 +91,7 @@ func (ecc *eventCalendarCache) AddToCache(ctx context.Context, f graph.Container
return errors.Wrap(err, "validating container") return errors.Wrap(err, "validating container")
} }
temp := graph.NewCacheFolder(f, path.Builder{}.Append(*f.GetDisplayName())) temp := graph.NewCacheFolder(f, path.Builder{}.Append(calendarOthersFolder, *f.GetDisplayName()))
if err := ecc.addFolder(temp); err != nil { if err := ecc.addFolder(temp); err != nil {
return errors.Wrap(err, "adding container") return errors.Wrap(err, "adding container")

View File

@ -38,4 +38,5 @@ const (
rootFolderAlias = "msgfolderroot" rootFolderAlias = "msgfolderroot"
DefaultContactFolder = "Contacts" DefaultContactFolder = "Contacts"
DefaultCalendar = "Calendar" DefaultCalendar = "Calendar"
calendarOthersFolder = "Other Calendars"
) )

View File

@ -645,7 +645,11 @@ func establishEventsRestoreLocation(
user string, user string,
isNewCache bool, isNewCache bool,
) (string, error) { ) (string, error) {
cached, ok := ecc.PathInCache(folders[0]) // Need to prefix with the "Other Calendars" folder so lookup happens properly.
cached, ok := ecc.PathInCache(path.Builder{}.Append(
calendarOthersFolder,
folders[0],
).String())
if ok { if ok {
return cached, nil return cached, nil
} }