Remove fallback reasons and merge code for legacy UPN tagged backups
This commit is contained in:
parent
0e6ef90e41
commit
fdc9145f61
@ -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,
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user