Backup list filtering (#3979)
Now that we store backup models for backups that had errors filter them out during backup list. This ensures behavior doesn't change when we merge PRs for making and labeling backup models with the assist backup tag --- #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [x] ⛔ No #### Type of change - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Supportability/Tests - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup #### Issue(s) * #3973 #### Test Plan - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
95197872c5
commit
9ec638f763
@ -449,7 +449,7 @@ func getBackup(
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// BackupsByID lists backups by ID. Returns as many backups as possible with
|
||||
// Backups lists backups by ID. Returns as many backups as possible with
|
||||
// errors for the backups it was unable to retrieve.
|
||||
func (r repository) Backups(ctx context.Context, ids []string) ([]*backup.Backup, *fault.Bus) {
|
||||
var (
|
||||
@ -472,10 +472,38 @@ func (r repository) Backups(ctx context.Context, ids []string) ([]*backup.Backup
|
||||
return bups, errs
|
||||
}
|
||||
|
||||
// backups lists backups in a repository
|
||||
// BackupsByTag lists all backups in a repository that contain all the tags
|
||||
// specified.
|
||||
func (r repository) BackupsByTag(ctx context.Context, fs ...store.FilterOption) ([]*backup.Backup, error) {
|
||||
sw := store.NewKopiaStore(r.modelStore)
|
||||
return sw.GetBackups(ctx, fs...)
|
||||
return backupsByTag(ctx, sw, fs)
|
||||
}
|
||||
|
||||
// backupsByTag returns all backups matching all provided tags.
|
||||
//
|
||||
// TODO(ashmrtn): This exists mostly for testing, but we could restructure the
|
||||
// code in this file so there's a more elegant mocking solution.
|
||||
func backupsByTag(
|
||||
ctx context.Context,
|
||||
sw store.BackupWrapper,
|
||||
fs []store.FilterOption,
|
||||
) ([]*backup.Backup, error) {
|
||||
bs, err := sw.GetBackups(ctx, fs...)
|
||||
if err != nil {
|
||||
return nil, clues.Stack(err)
|
||||
}
|
||||
|
||||
// Filter out assist backup bases as they're considered incomplete and we
|
||||
// haven't been displaying them before now.
|
||||
res := make([]*backup.Backup, 0, len(bs))
|
||||
|
||||
for _, b := range bs {
|
||||
if t := b.Tags[model.BackupTypeTag]; t != model.AssistBackup {
|
||||
res = append(res, b)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// BackupDetails returns the specified backup.Details
|
||||
|
||||
@ -30,6 +30,41 @@ import (
|
||||
"github.com/alcionai/corso/src/pkg/store/mock"
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mocks
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type mockBackupList struct {
|
||||
backups []*backup.Backup
|
||||
err error
|
||||
check func(fs []store.FilterOption)
|
||||
}
|
||||
|
||||
func (mbl mockBackupList) GetBackup(
|
||||
ctx context.Context,
|
||||
backupID model.StableID,
|
||||
) (*backup.Backup, error) {
|
||||
return nil, clues.New("not implemented")
|
||||
}
|
||||
|
||||
func (mbl mockBackupList) DeleteBackup(
|
||||
ctx context.Context,
|
||||
backupID model.StableID,
|
||||
) error {
|
||||
return clues.New("not implemented")
|
||||
}
|
||||
|
||||
func (mbl mockBackupList) GetBackups(
|
||||
ctx context.Context,
|
||||
filters ...store.FilterOption,
|
||||
) ([]*backup.Backup, error) {
|
||||
if mbl.check != nil {
|
||||
mbl.check(filters)
|
||||
}
|
||||
|
||||
return mbl.backups, mbl.err
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Unit
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -100,6 +135,191 @@ func (suite *RepositoryBackupsUnitSuite) TestGetBackup() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *RepositoryBackupsUnitSuite) TestBackupsByTag() {
|
||||
unlabeled1 := &backup.Backup{
|
||||
BaseModel: model.BaseModel{
|
||||
ID: model.StableID(uuid.NewString()),
|
||||
},
|
||||
}
|
||||
unlabeled2 := &backup.Backup{
|
||||
BaseModel: model.BaseModel{
|
||||
ID: model.StableID(uuid.NewString()),
|
||||
},
|
||||
}
|
||||
|
||||
merge1 := &backup.Backup{
|
||||
BaseModel: model.BaseModel{
|
||||
ID: model.StableID(uuid.NewString()),
|
||||
Tags: map[string]string{
|
||||
model.BackupTypeTag: model.MergeBackup,
|
||||
},
|
||||
},
|
||||
}
|
||||
merge2 := &backup.Backup{
|
||||
BaseModel: model.BaseModel{
|
||||
ID: model.StableID(uuid.NewString()),
|
||||
Tags: map[string]string{
|
||||
model.BackupTypeTag: model.MergeBackup,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assist1 := &backup.Backup{
|
||||
BaseModel: model.BaseModel{
|
||||
ID: model.StableID(uuid.NewString()),
|
||||
Tags: map[string]string{
|
||||
model.BackupTypeTag: model.AssistBackup,
|
||||
},
|
||||
},
|
||||
}
|
||||
assist2 := &backup.Backup{
|
||||
BaseModel: model.BaseModel{
|
||||
ID: model.StableID(uuid.NewString()),
|
||||
Tags: map[string]string{
|
||||
model.BackupTypeTag: model.AssistBackup,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
getBackups []*backup.Backup
|
||||
filters []store.FilterOption
|
||||
listErr error
|
||||
expectErr assert.ErrorAssertionFunc
|
||||
expect []*backup.Backup
|
||||
}{
|
||||
{
|
||||
name: "UnlabeledOnly",
|
||||
getBackups: []*backup.Backup{
|
||||
unlabeled1,
|
||||
unlabeled2,
|
||||
},
|
||||
expectErr: assert.NoError,
|
||||
expect: []*backup.Backup{
|
||||
unlabeled1,
|
||||
unlabeled2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MergeOnly",
|
||||
getBackups: []*backup.Backup{
|
||||
merge1,
|
||||
merge2,
|
||||
},
|
||||
expectErr: assert.NoError,
|
||||
expect: []*backup.Backup{
|
||||
merge1,
|
||||
merge2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AssistOnly",
|
||||
getBackups: []*backup.Backup{
|
||||
assist1,
|
||||
assist2,
|
||||
},
|
||||
expectErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
name: "UnlabledAndMerge",
|
||||
getBackups: []*backup.Backup{
|
||||
merge1,
|
||||
unlabeled1,
|
||||
merge2,
|
||||
unlabeled2,
|
||||
},
|
||||
expectErr: assert.NoError,
|
||||
expect: []*backup.Backup{
|
||||
merge1,
|
||||
merge2,
|
||||
unlabeled1,
|
||||
unlabeled2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "UnlabeledAndAssist",
|
||||
getBackups: []*backup.Backup{
|
||||
unlabeled1,
|
||||
assist1,
|
||||
unlabeled2,
|
||||
assist2,
|
||||
},
|
||||
expectErr: assert.NoError,
|
||||
expect: []*backup.Backup{
|
||||
unlabeled1,
|
||||
unlabeled2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MergeAndAssist",
|
||||
getBackups: []*backup.Backup{
|
||||
merge1,
|
||||
assist1,
|
||||
merge2,
|
||||
assist2,
|
||||
},
|
||||
expectErr: assert.NoError,
|
||||
expect: []*backup.Backup{
|
||||
merge1,
|
||||
merge2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "UnlabeledAndMergeAndAssist",
|
||||
getBackups: []*backup.Backup{
|
||||
unlabeled1,
|
||||
merge1,
|
||||
assist1,
|
||||
merge2,
|
||||
unlabeled2,
|
||||
assist2,
|
||||
},
|
||||
expectErr: assert.NoError,
|
||||
expect: []*backup.Backup{
|
||||
merge1,
|
||||
merge2,
|
||||
unlabeled1,
|
||||
unlabeled2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LookupError",
|
||||
getBackups: []*backup.Backup{
|
||||
unlabeled1,
|
||||
merge1,
|
||||
assist1,
|
||||
merge2,
|
||||
unlabeled2,
|
||||
assist2,
|
||||
},
|
||||
listErr: assert.AnError,
|
||||
expectErr: assert.Error,
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
ctx, flush := tester.NewContext(t)
|
||||
defer flush()
|
||||
|
||||
mbl := mockBackupList{
|
||||
backups: test.getBackups,
|
||||
err: test.listErr,
|
||||
check: func(fs []store.FilterOption) {
|
||||
assert.ElementsMatch(t, test.filters, fs)
|
||||
},
|
||||
}
|
||||
|
||||
bs, err := backupsByTag(ctx, mbl, test.filters)
|
||||
test.expectErr(t, err, clues.ToCore(err))
|
||||
|
||||
assert.ElementsMatch(t, test.expect, bs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockSSDeleter struct {
|
||||
err error
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user