diff --git a/src/internal/kopia/backup_bases.go b/src/internal/kopia/backup_bases.go index 4c2c95fb7..be94c6167 100644 --- a/src/internal/kopia/backup_bases.go +++ b/src/internal/kopia/backup_bases.go @@ -8,7 +8,6 @@ import ( "golang.org/x/exp/slices" "github.com/alcionai/corso/src/internal/version" - "github.com/alcionai/corso/src/pkg/backup/identity" "github.com/alcionai/corso/src/pkg/logger" ) @@ -23,11 +22,6 @@ type BackupBases interface { ClearMergeBases() AssistBases() []ManifestEntry ClearAssistBases() - MergeBackupBases( - ctx context.Context, - other BackupBases, - reasonToKey func(identity.Reasoner) string, - ) BackupBases } type backupBases struct { @@ -111,119 +105,6 @@ func (bb *backupBases) ClearAssistBases() { bb.assistBases = nil } -// MergeBackupBases reduces the two BackupBases into a single BackupBase. -// Assumes the passed in BackupBases represents a prior backup version (across -// some migration that disrupts lookup), and that the BackupBases used to call -// this function contains the current version. -// -// reasonToKey should be a function that, given a Reasoner, will produce some -// string that represents Reasoner in the context of the merge operation. For -// example, to merge BackupBases across a ProtectedResource migration, the -// Reasoner's service and category can be used as the key. -// -// Selection priority, for each reason key generated by reasonsToKey, follows -// these rules: -// 1. If the called BackupBases has an entry for a given reason, ignore the -// other BackupBases matching that reason. -// 2. If the called BackupBases has only AssistBases, look for a matching -// MergeBase manifest in the other BackupBases. -// 3. If the called BackupBases has no entry for a reason, look for a matching -// MergeBase in the other BackupBases. -func (bb *backupBases) MergeBackupBases( - ctx context.Context, - other BackupBases, - reasonToKey func(reason identity.Reasoner) string, -) BackupBases { - if other == nil || (len(other.MergeBases()) == 0 && len(other.AssistBases()) == 0) { - return bb - } - - if bb == nil || (len(bb.MergeBases()) == 0 && len(bb.AssistBases()) == 0) { - return other - } - - toMerge := map[string]struct{}{} - assist := map[string]struct{}{} - - // Track the bases in bb. - for _, m := range bb.mergeBases { - for _, r := range m.Reasons { - k := reasonToKey(r) - - toMerge[k] = struct{}{} - assist[k] = struct{}{} - } - } - - for _, m := range bb.assistBases { - for _, r := range m.Reasons { - k := reasonToKey(r) - assist[k] = struct{}{} - } - } - - var toAdd []ManifestEntry - - // Calculate the set of mergeBases to pull from other into this one. - for _, m := range other.MergeBases() { - useReasons := []identity.Reasoner{} - - for _, r := range m.Reasons { - k := reasonToKey(r) - if _, ok := toMerge[k]; ok { - // Assume other contains prior manifest versions. - // We don't want to stack a prior version incomplete onto - // a current version's complete snapshot. - continue - } - - useReasons = append(useReasons, r) - } - - if len(useReasons) > 0 { - m.Reasons = useReasons - toAdd = append(toAdd, m) - } - } - - res := &backupBases{ - backups: bb.Backups(), - mergeBases: bb.MergeBases(), - assistBases: bb.AssistBases(), - // Note that assistBackups are a new feature and don't exist - // in prior versions where we were using UPN based reasons i.e. - // other won't have any assistBackups. - assistBackups: bb.AssistBackups(), - } - - // Add new mergeBases and backups. - for _, man := range toAdd { - // Will get empty string if not found which is fine, it'll fail one of the - // other checks. - bID, _ := man.GetTag(TagBackupID) - - bup, ok := getBackupByID(other.Backups(), bID) - if !ok { - logger.Ctx(ctx).Infow( - "not unioning snapshot missing backup", - "other_manifest_id", man.ID, - "other_backup_id", bID) - - continue - } - - bup.Reasons = man.Reasons - - res.backups = append(res.backups, bup) - res.mergeBases = append(res.mergeBases, man) - // TODO(pandeyabs): Remove this once we remove overlap between - // between merge and assist bases as part of #3943. - res.assistBases = append(res.assistBases, man) - } - - return res -} - func findNonUniqueManifests( ctx context.Context, manifests []ManifestEntry, diff --git a/src/internal/kopia/backup_bases_test.go b/src/internal/kopia/backup_bases_test.go index faa402162..3b0fc91cc 100644 --- a/src/internal/kopia/backup_bases_test.go +++ b/src/internal/kopia/backup_bases_test.go @@ -1,7 +1,6 @@ package kopia import ( - "fmt" "testing" "github.com/kopia/kopia/repo/manifest" @@ -203,279 +202,6 @@ func (suite *BackupBasesUnitSuite) TestClearAssistBases() { assert.Empty(suite.T(), bb.AssistBases()) } -func (suite *BackupBasesUnitSuite) TestMergeBackupBases() { - ro := "resource_owner" - - type testInput struct { - id int - cat []path.CategoryType - } - - // Make a function so tests can modify things without messing with each other. - makeBackupBases := func(mergeInputs []testInput, assistInputs []testInput) *backupBases { - res := &backupBases{} - - for _, i := range mergeInputs { - baseID := fmt.Sprintf("id%d", i.id) - reasons := make([]identity.Reasoner, 0, len(i.cat)) - - for _, c := range i.cat { - reasons = append(reasons, NewReason("", ro, path.ExchangeService, c)) - } - - m := makeManifest(baseID, "", "b"+baseID, reasons...) - res.assistBases = append(res.assistBases, m) - - b := BackupEntry{ - Backup: &backup.Backup{ - BaseModel: model.BaseModel{ID: model.StableID("b" + baseID)}, - SnapshotID: baseID, - StreamStoreID: "ss" + baseID, - }, - Reasons: reasons, - } - - res.backups = append(res.backups, b) - res.mergeBases = append(res.mergeBases, m) - } - - for _, i := range assistInputs { - baseID := fmt.Sprintf("id%d", i.id) - - reasons := make([]identity.Reasoner, 0, len(i.cat)) - - for _, c := range i.cat { - reasons = append(reasons, NewReason("", ro, path.ExchangeService, c)) - } - - m := makeManifest(baseID, "", "a"+baseID, reasons...) - - b := BackupEntry{ - Backup: &backup.Backup{ - BaseModel: model.BaseModel{ - ID: model.StableID("a" + baseID), - Tags: map[string]string{model.BackupTypeTag: model.AssistBackup}, - }, - SnapshotID: baseID, - StreamStoreID: "ss" + baseID, - }, - Reasons: reasons, - } - - res.assistBackups = append(res.assistBackups, b) - res.assistBases = append(res.assistBases, m) - } - - return res - } - - table := []struct { - name string - merge []testInput - assist []testInput - otherMerge []testInput - otherAssist []testInput - expect func() *backupBases - }{ - { - name: "Other Empty", - merge: []testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - }, - assist: []testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - }, - expect: func() *backupBases { - bs := makeBackupBases([]testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - }, []testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - }) - - return bs - }, - }, - { - name: "current Empty", - otherMerge: []testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - }, - otherAssist: []testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - }, - expect: func() *backupBases { - bs := makeBackupBases([]testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - }, []testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - }) - - return bs - }, - }, - { - name: "Other overlaps merge and assist", - merge: []testInput{ - { - id: 1, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - assist: []testInput{ - { - id: 4, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - otherMerge: []testInput{ - { - id: 2, - cat: []path.CategoryType{path.EmailCategory}, - }, - { - id: 3, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - otherAssist: []testInput{ - { - id: 5, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - expect: func() *backupBases { - bs := makeBackupBases([]testInput{ - { - id: 1, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, []testInput{ - { - id: 4, - cat: []path.CategoryType{path.EmailCategory}, - }, - }) - - return bs - }, - }, - { - name: "Other overlaps merge", - merge: []testInput{ - { - id: 1, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - otherMerge: []testInput{ - { - id: 2, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - expect: func() *backupBases { - bs := makeBackupBases([]testInput{ - { - id: 1, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, nil) - - return bs - }, - }, - { - name: "Current assist overlaps with Other merge", - assist: []testInput{ - { - id: 3, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - otherMerge: []testInput{ - { - id: 1, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - otherAssist: []testInput{ - { - id: 2, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - - expect: func() *backupBases { - bs := makeBackupBases([]testInput{ - { - id: 1, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, []testInput{ - { - id: 3, - cat: []path.CategoryType{path.EmailCategory}, - }, - }) - - return bs - }, - }, - { - name: "Other Disjoint", - merge: []testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - { - id: 1, - cat: []path.CategoryType{path.EmailCategory}, - }, - }, - otherMerge: []testInput{ - { - id: 2, - cat: []path.CategoryType{path.ContactsCategory}, - }, - }, - expect: func() *backupBases { - bs := makeBackupBases([]testInput{ - {cat: []path.CategoryType{path.EmailCategory}}, - { - id: 1, - cat: []path.CategoryType{path.EmailCategory}, - }, - { - id: 2, - cat: []path.CategoryType{path.ContactsCategory}, - }, - }, nil) - - return bs - }, - }, - } - - for _, test := range table { - suite.Run(test.name, func() { - t := suite.T() - - bb := makeBackupBases(test.merge, test.assist) - other := makeBackupBases(test.otherMerge, test.otherAssist) - expected := test.expect() - - ctx, flush := tester.NewContext(t) - defer flush() - - got := bb.MergeBackupBases( - ctx, - other, - func(r identity.Reasoner) string { - return r.Service().String() + r.Category().String() - }) - AssertBackupBasesEqual(t, expected, got) - }) - } -} - func (suite *BackupBasesUnitSuite) TestFixupAndVerify() { ro := "resource_owner" diff --git a/src/internal/operations/backup.go b/src/internal/operations/backup.go index d3d4f0a9f..5cf810066 100644 --- a/src/internal/operations/backup.go +++ b/src/internal/operations/backup.go @@ -333,11 +333,6 @@ func (op *BackupOperation) do( return nil, clues.Wrap(err, "getting reasons") } - fallbackReasons, err := makeFallbackReasons(op.account.ID(), op.Selectors) - if err != nil { - return nil, clues.Wrap(err, "getting fallback reasons") - } - logger.Ctx(ctx).With( "control_options", op.Options, "selectors", op.Selectors). @@ -355,7 +350,7 @@ func (op *BackupOperation) do( ctx, kbf, op.kopia, - reasons, fallbackReasons, + reasons, op.account.ID(), op.incremental, op.disableAssistBackup) @@ -430,16 +425,6 @@ func (op *BackupOperation) do( return deets, nil } -func makeFallbackReasons(tenant string, sel selectors.Selector) ([]identity.Reasoner, error) { - if sel.PathService() != path.SharePointService && - sel.DiscreteOwner != sel.DiscreteOwnerName { - return sel.Reasons(tenant, true) - } - - // return nil for fallback reasons since a nil value will no-op. - return nil, nil -} - // checker to see if conditions are correct for incremental backup behavior such as // retrieving metadata like delta tokens and previous paths. func useIncrementalBackup(sel selectors.Selector, opts control.Options) bool { diff --git a/src/internal/operations/manifests.go b/src/internal/operations/manifests.go index 95b313adc..060e7aab5 100644 --- a/src/internal/operations/manifests.go +++ b/src/internal/operations/manifests.go @@ -20,7 +20,7 @@ func produceManifestsAndMetadata( ctx context.Context, bf inject.BaseFinder, rp inject.RestoreProducer, - reasons, fallbackReasons []identity.Reasoner, + reasons []identity.Reasoner, tenantID string, getMetadata, dropAssistBases bool, ) (kopia.BackupBases, []data.RestoreCollection, bool, error) { @@ -29,7 +29,6 @@ func produceManifestsAndMetadata( bf, rp, reasons, - fallbackReasons, tenantID, getMetadata) if err != nil { @@ -57,7 +56,7 @@ func getManifestsAndMetadata( ctx context.Context, bf inject.BaseFinder, rp inject.RestoreProducer, - reasons, fallbackReasons []identity.Reasoner, + reasons []identity.Reasoner, tenantID string, getMetadata bool, ) (kopia.BackupBases, []data.RestoreCollection, bool, error) { @@ -68,24 +67,6 @@ func getManifestsAndMetadata( ) bb := bf.FindBases(ctx, reasons, tags) - // TODO(ashmrtn): Only fetch these if we haven't already covered all the - // reasons for this backup. - fbb := bf.FindBases(ctx, fallbackReasons, tags) - - // one of three cases can occur when retrieving backups across reason migrations: - // 1. the current reasons don't match any manifests, and we use the fallback to - // look up the previous reason version. - // 2. the current reasons only contain an incomplete manifest, and the fallback - // can find a complete manifest. - // 3. the current reasons contain all the necessary manifests. - // Note: This is not relevant for assist backups, since they are newly introduced - // and they don't exist with fallback reasons. - bb = bb.MergeBackupBases( - ctx, - fbb, - func(r identity.Reasoner) string { - return r.Service().String() + r.Category().String() - }) if !getMetadata { return bb, nil, false, nil diff --git a/src/internal/operations/manifests_test.go b/src/internal/operations/manifests_test.go index d6e284750..fd3298e20 100644 --- a/src/internal/operations/manifests_test.go +++ b/src/internal/operations/manifests_test.go @@ -12,9 +12,7 @@ import ( "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/kopia" - "github.com/alcionai/corso/src/internal/model" "github.com/alcionai/corso/src/internal/tester" - "github.com/alcionai/corso/src/pkg/backup" "github.com/alcionai/corso/src/pkg/backup/identity" "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" @@ -482,7 +480,7 @@ func (suite *OperationsManifestsUnitSuite) TestProduceManifestsAndMetadata() { ctx, test.bf, &test.rp, - test.reasons, nil, + test.reasons, tid, test.getMeta, test.dropAssist) @@ -532,499 +530,3 @@ func (suite *OperationsManifestsUnitSuite) TestProduceManifestsAndMetadata() { }) } } - -func (suite *OperationsManifestsUnitSuite) TestProduceManifestsAndMetadata_FallbackReasons() { - const ( - ro = "resourceowner" - fbro = "fb_resourceowner" - tid = "tenantid" - did = "detailsid" - ) - - makeMan := func(ro, id, incmpl string, cats ...path.CategoryType) kopia.ManifestEntry { - return kopia.ManifestEntry{ - Manifest: &snapshot.Manifest{ - ID: manifest.ID(id), - IncompleteReason: incmpl, - Tags: map[string]string{"tag:" + kopia.TagBackupID: id + "bup"}, - }, - Reasons: buildReasons(ro, path.ExchangeService, cats...), - } - } - - makeBackup := func(ro, snapID string, cats ...path.CategoryType) kopia.BackupEntry { - return kopia.BackupEntry{ - Backup: &backup.Backup{ - BaseModel: model.BaseModel{ - ID: model.StableID(snapID + "bup"), - }, - SnapshotID: snapID, - StreamStoreID: snapID + "store", - }, - Reasons: buildReasons(ro, path.ExchangeService, cats...), - } - } - - emailReason := kopia.NewReason( - "", - ro, - path.ExchangeService, - path.EmailCategory) - - fbEmailReason := kopia.NewReason( - "", - fbro, - path.ExchangeService, - path.EmailCategory) - - table := []struct { - name string - bf *mockBackupFinder - rp mockRestoreProducer - reasons []identity.Reasoner - fallbackReasons []identity.Reasoner - getMeta bool - dropAssist bool - assertErr assert.ErrorAssertionFunc - assertB assert.BoolAssertionFunc - expectDCS []mockColl - expectMans kopia.BackupBases - }{ - { - name: "don't get metadata, only fallbacks", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ), - }, - }, - rp: mockRestoreProducer{}, - fallbackReasons: []identity.Reasoner{fbEmailReason}, - getMeta: false, - assertErr: assert.NoError, - assertB: assert.False, - expectDCS: nil, - expectMans: kopia.NewMockBackupBases().WithAssistBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ), - }, - { - name: "only fallbacks", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "fb_id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id1"}}}, - }, - }, - fallbackReasons: []identity.Reasoner{fbEmailReason}, - getMeta: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "fb_id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ), - }, - { - name: "only fallbacks, no assist", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "fb_id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id1"}}}, - }, - }, - fallbackReasons: []identity.Reasoner{fbEmailReason}, - getMeta: true, - dropAssist: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "fb_id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ). - ClearMockAssistBases(), - }, - { - name: "complete mans and fallbacks", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - ro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - ), - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id1"}}}, - "fb_id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id1"}}}, - }, - }, - reasons: []identity.Reasoner{emailReason}, - fallbackReasons: []identity.Reasoner{fbEmailReason}, - getMeta: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - ), - }, - { - name: "incomplete mans and fallbacks", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - ro: kopia.NewMockBackupBases().WithAssistBases( - makeMan(ro, "id2", "checkpoint", path.EmailCategory), - ), - fbro: kopia.NewMockBackupBases().WithAssistBases( - makeMan(fbro, "fb_id2", "checkpoint", path.EmailCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "id2": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id2"}}}, - "fb_id2": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id2"}}}, - }, - }, - reasons: []identity.Reasoner{emailReason}, - fallbackReasons: []identity.Reasoner{fbEmailReason}, - getMeta: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: nil, - expectMans: kopia.NewMockBackupBases().WithAssistBases( - makeMan(ro, "id2", "checkpoint", path.EmailCategory), - ), - }, - { - name: "complete and incomplete mans and fallbacks", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - ro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - ).WithAssistBases( - makeMan(ro, "id2", "checkpoint", path.EmailCategory), - ), - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ).WithAssistBases( - makeMan(fbro, "fb_id2", "checkpoint", path.EmailCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id1"}}}, - "id2": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id2"}}}, - "fb_id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id1"}}}, - "fb_id2": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id2"}}}, - }, - }, - reasons: []identity.Reasoner{emailReason}, - fallbackReasons: []identity.Reasoner{fbEmailReason}, - getMeta: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - ).WithAssistBases( - makeMan(ro, "id2", "checkpoint", path.EmailCategory), - ), - }, - { - name: "incomplete mans and complete fallbacks", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - ro: kopia.NewMockBackupBases().WithAssistBases( - makeMan(ro, "id2", "checkpoint", path.EmailCategory), - ), - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "id2": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id2"}}}, - "fb_id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id1"}}}, - }, - }, - reasons: []identity.Reasoner{emailReason}, - fallbackReasons: []identity.Reasoner{fbEmailReason}, - getMeta: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "fb_id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ).WithAssistBases( - makeMan(ro, "id2", "checkpoint", path.EmailCategory), - ), - }, - { - name: "incomplete mans and complete fallbacks, no assist bases", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - ro: kopia.NewMockBackupBases().WithAssistBases( - makeMan(ro, "id2", "checkpoint", path.EmailCategory), - ), - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "id2": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id2"}}}, - "fb_id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id1"}}}, - }, - }, - reasons: []identity.Reasoner{emailReason}, - fallbackReasons: []identity.Reasoner{fbEmailReason}, - getMeta: true, - dropAssist: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "fb_id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory), - ). - ClearMockAssistBases(), - }, - { - name: "complete mans and incomplete fallbacks", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - ro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - ), - fbro: kopia.NewMockBackupBases().WithAssistBases( - makeMan(fbro, "fb_id2", "checkpoint", path.EmailCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id1"}}}, - "fb_id2": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id2"}}}, - }, - }, - reasons: []identity.Reasoner{emailReason}, - fallbackReasons: []identity.Reasoner{fbEmailReason}, - getMeta: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - ), - }, - { - name: "complete mans and complete fallbacks, multiple reasons", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - ro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory, path.ContactsCategory), - ), - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory, path.ContactsCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory, path.ContactsCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id1"}}}, - "fb_id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id1"}}}, - }, - }, - reasons: []identity.Reasoner{ - emailReason, - kopia.NewReason("", ro, path.ExchangeService, path.ContactsCategory), - }, - fallbackReasons: []identity.Reasoner{ - fbEmailReason, - kopia.NewReason("", fbro, path.ExchangeService, path.ContactsCategory), - }, - getMeta: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory, path.ContactsCategory), - ), - }, - { - name: "complete mans and complete fallbacks, distinct reasons", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - ro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - ), - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.ContactsCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.ContactsCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id1"}}}, - "fb_id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id1"}}}, - }, - }, - reasons: []identity.Reasoner{emailReason}, - fallbackReasons: []identity.Reasoner{ - kopia.NewReason("", fbro, path.ExchangeService, path.ContactsCategory), - }, - getMeta: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "id1"}, {id: "fb_id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - makeMan(fbro, "fb_id1", "", path.ContactsCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.ContactsCategory), - ), - }, - { - name: "complete mans and complete fallbacks, fallback has superset of reasons", - bf: &mockBackupFinder{ - data: map[string]kopia.BackupBases{ - ro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - ), - fbro: kopia.NewMockBackupBases().WithMergeBases( - makeMan(fbro, "fb_id1", "", path.EmailCategory, path.ContactsCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.EmailCategory, path.ContactsCategory), - ), - }, - }, - rp: mockRestoreProducer{ - collsByID: map[string][]data.RestoreCollection{ - "id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "id1"}}}, - "fb_id1": {data.NoFetchRestoreCollection{Collection: mockColl{id: "fb_id1"}}}, - }, - }, - reasons: []identity.Reasoner{ - emailReason, - kopia.NewReason("", ro, path.ExchangeService, path.ContactsCategory), - }, - fallbackReasons: []identity.Reasoner{ - fbEmailReason, - kopia.NewReason("", fbro, path.ExchangeService, path.ContactsCategory), - }, - getMeta: true, - assertErr: assert.NoError, - assertB: assert.True, - expectDCS: []mockColl{{id: "id1"}, {id: "fb_id1"}}, - expectMans: kopia.NewMockBackupBases().WithMergeBases( - makeMan(ro, "id1", "", path.EmailCategory), - makeMan(fbro, "fb_id1", "", path.ContactsCategory), - ).WithBackups( - makeBackup(fbro, "fb_id1", path.ContactsCategory), - ), - }, - } - - for _, test := range table { - suite.Run(test.name, func() { - t := suite.T() - - ctx, flush := tester.NewContext(t) - defer flush() - - mans, dcs, b, err := produceManifestsAndMetadata( - ctx, - test.bf, - &test.rp, - test.reasons, test.fallbackReasons, - tid, - test.getMeta, - test.dropAssist) - test.assertErr(t, err, clues.ToCore(err)) - test.assertB(t, b) - - kopia.AssertBackupBasesEqual(t, test.expectMans, mans) - - expect, got := []string{}, []string{} - - for _, dc := range test.expectDCS { - expect = append(expect, dc.id) - } - - for _, dc := range dcs { - if !assert.IsTypef( - t, - data.NoFetchRestoreCollection{}, - dc, - "unexpected type returned [%T]", - dc, - ) { - continue - } - - tmp := dc.(data.NoFetchRestoreCollection) - - if !assert.IsTypef( - t, - mockColl{}, - tmp.Collection, - "unexpected type returned [%T]", - tmp.Collection, - ) { - continue - } - - mc := tmp.Collection.(mockColl) - got = append(got, mc.id) - } - - assert.ElementsMatch(t, expect, got, "expected collections are present") - }) - } -}