From 66eb789d39f9f05767720ffc8e36f0999cba3654 Mon Sep 17 00:00:00 2001 From: ashmrtn <3891298+ashmrtn@users.noreply.github.com> Date: Tue, 31 Oct 2023 18:06:50 -0700 Subject: [PATCH] Helper function to get backup type (#4591) Allow the backup model to tell us what type it was tagged with. This will make logic for base selection easier since it won't have to worry about extracting the type anymore. --- #### Does this PR need a docs update or release note? - [ ] :white_check_mark: Yes, it's included - [ ] :clock1: Yes, but in a later PR - [x] :no_entry: No #### Type of change - [x] :sunflower: Feature - [ ] :bug: Bugfix - [ ] :world_map: Documentation - [ ] :robot: Supportability/Tests - [ ] :computer: CI/Deployment - [ ] :broom: Tech Debt/Cleanup #### Test Plan - [ ] :muscle: Manual - [x] :zap: Unit test - [ ] :green_heart: E2E --- src/pkg/backup/backup.go | 25 ++++++++++- src/pkg/backup/backup_test.go | 80 +++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/pkg/backup/backup.go b/src/pkg/backup/backup.go index 6a9a27a7b..4a6674d7b 100644 --- a/src/pkg/backup/backup.go +++ b/src/pkg/backup/backup.go @@ -14,6 +14,7 @@ import ( "github.com/alcionai/corso/src/internal/common/str" "github.com/alcionai/corso/src/internal/model" "github.com/alcionai/corso/src/internal/stats" + "github.com/alcionai/corso/src/internal/version" "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/selectors" ) @@ -72,7 +73,7 @@ var _ print.Printable = &Backup{} func New( snapshotID, streamStoreID, status string, - version int, + backupVersion int, id model.StableID, selector selectors.Selector, ownerID, ownerName string, @@ -118,7 +119,7 @@ func New( ResourceOwnerID: ownerID, ResourceOwnerName: ownerName, - Version: version, + Version: backupVersion, SnapshotID: snapshotID, StreamStoreID: streamStoreID, @@ -141,6 +142,26 @@ func New( } } +// Type returns the type of the backup according to the value stored in the +// Backup's tags. Backup type is used during base finding to determine if a +// given backup is eligible to be used for the upcoming incremental backup. +func (b Backup) Type() string { + t, ok := b.Tags[model.BackupTypeTag] + + // Older backups didn't set the backup type tag because we only persisted + // backup models for the MergeBackup type. Corso started adding the backup + // type tag when it was producing v8 backups. Any backup newer than that that + // doesn't have a backup type should just return an empty type and let the + // caller figure out what to do. + if !ok && + b.Version != version.NoBackup && + b.Version <= version.All8MigrateUserPNToID { + t = model.MergeBackup + } + + return t +} + // -------------------------------------------------------------------------------- // CLI Output // -------------------------------------------------------------------------------- diff --git a/src/pkg/backup/backup_test.go b/src/pkg/backup/backup_test.go index c1ce6f1cf..f9de49e70 100644 --- a/src/pkg/backup/backup_test.go +++ b/src/pkg/backup/backup_test.go @@ -1,6 +1,7 @@ package backup_test import ( + "fmt" "strconv" "testing" "time" @@ -14,6 +15,7 @@ import ( "github.com/alcionai/corso/src/internal/model" "github.com/alcionai/corso/src/internal/stats" "github.com/alcionai/corso/src/internal/tester" + "github.com/alcionai/corso/src/internal/version" "github.com/alcionai/corso/src/pkg/backup" "github.com/alcionai/corso/src/pkg/selectors" ) @@ -26,6 +28,84 @@ func TestBackupUnitSuite(t *testing.T) { suite.Run(t, &BackupUnitSuite{Suite: tester.NewUnitSuite(t)}) } +func (suite *BackupUnitSuite) TestBackup_Type() { + table := []struct { + name string + // versionStart is the first version to run this test on. Together with + // versionEnd this allows more compact test definition when the behavior is + // the same for multiple versions. + versionStart int + // versionEnd is the final version to run this test on. Together with + // versionStart this allows more compact test definition when the behavior + // is the same for multiple versions. + versionEnd int + // Take a map so that we can have check not having the tag at all vs. having + // an empty value. + inputTags map[string]string + expect string + }{ + { + name: "NoVersion Returns Empty Type If Untagged", + versionStart: version.NoBackup, + versionEnd: version.NoBackup, + }, + { + name: "PreTag Versions Returns Merge Type If Untagged", + versionStart: 0, + versionEnd: version.All8MigrateUserPNToID, + expect: model.MergeBackup, + }, + { + name: "Tag Versions Returns Merge Type If Tagged", + versionStart: version.All8MigrateUserPNToID, + versionEnd: version.Backup, + inputTags: map[string]string{ + model.BackupTypeTag: model.MergeBackup, + }, + expect: model.MergeBackup, + }, + { + name: "Tag Versions Returns Assist Type If Tagged", + versionStart: version.All8MigrateUserPNToID, + versionEnd: version.Backup, + inputTags: map[string]string{ + model.BackupTypeTag: model.AssistBackup, + }, + expect: model.AssistBackup, + }, + { + name: "Tag Versions Returns Empty Type If Untagged", + versionStart: version.Groups9Update, + versionEnd: version.Backup, + }, + { + name: "All Versions Returns Empty Type If Empty Tag", + versionStart: 0, + versionEnd: version.Backup, + inputTags: map[string]string{ + model.BackupTypeTag: "", + }, + }, + } + + for _, test := range table { + suite.Run(test.name, func() { + for v := test.versionStart; v <= test.versionEnd; v++ { + suite.Run(fmt.Sprintf("Version%d", v), func() { + bup := backup.Backup{ + BaseModel: model.BaseModel{ + Tags: test.inputTags, + }, + Version: v, + } + + assert.Equal(suite.T(), test.expect, bup.Type()) + }) + } + }) + } +} + func stubBackup(t time.Time, ownerID, ownerName string) backup.Backup { sel := selectors.NewExchangeBackup([]string{"test"}) sel.Include(sel.AllData())