Backup details list exchange tests (#945)
## Description Add tests for the `backup list exchange` subcommand. Tests mostly center around indirectly testing how selectors are created and used in this subcommand by checking the output of running the `Reduce` call on a known set of `details.DetailsEntry`s. Also check various error cases Tests for invalid formats of flag values are disabled as that code does not currently exist. These tests can be enabled when #943 is resolved ## Type of change <!--- Please check the type of change your PR introduces: ---> - [ ] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [x] 🤖 Test - [ ] 💻 CI/Deployment - [ ] 🐹 Trivial/Minor ## Issue(s) * #913 ## Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
4d02650f99
commit
824f02469c
@ -1,6 +1,8 @@
|
|||||||
package backup
|
package backup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
@ -11,6 +13,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/cli/utils"
|
"github.com/alcionai/corso/src/cli/utils"
|
||||||
"github.com/alcionai/corso/src/internal/model"
|
"github.com/alcionai/corso/src/internal/model"
|
||||||
"github.com/alcionai/corso/src/pkg/backup"
|
"github.com/alcionai/corso/src/pkg/backup"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
"github.com/alcionai/corso/src/pkg/repository"
|
"github.com/alcionai/corso/src/pkg/repository"
|
||||||
"github.com/alcionai/corso/src/pkg/selectors"
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
@ -353,11 +356,6 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
defer utils.CloseRepo(ctx, r)
|
defer utils.CloseRepo(ctx, r)
|
||||||
|
|
||||||
d, _, err := r.BackupDetails(ctx, backupID)
|
|
||||||
if err != nil {
|
|
||||||
return Only(ctx, errors.Wrap(err, "Failed to get backup details in the repository"))
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := utils.ExchangeOpts{
|
opts := utils.ExchangeOpts{
|
||||||
Contacts: contact,
|
Contacts: contact,
|
||||||
ContactFolders: contactFolder,
|
ContactFolders: contactFolder,
|
||||||
@ -378,6 +376,34 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
|
|||||||
EventSubject: eventSubject,
|
EventSubject: eventSubject,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ds, err := runDetailsExchangeCmd(ctx, r, backupID, opts)
|
||||||
|
if err != nil {
|
||||||
|
return Only(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ds.Entries) == 0 {
|
||||||
|
Info(ctx, selectors.ErrorNoMatchingItems)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ds.PrintEntries(ctx)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// runDetailsExchangeCmd actually performs the lookup in backup details. Assumes
|
||||||
|
// len(backupID) > 0.
|
||||||
|
func runDetailsExchangeCmd(
|
||||||
|
ctx context.Context,
|
||||||
|
r repository.BackupGetter,
|
||||||
|
backupID string,
|
||||||
|
opts utils.ExchangeOpts,
|
||||||
|
) (*details.Details, error) {
|
||||||
|
d, _, err := r.BackupDetails(ctx, backupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Failed to get backup details in the repository")
|
||||||
|
}
|
||||||
|
|
||||||
sel := selectors.NewExchangeRestore()
|
sel := selectors.NewExchangeRestore()
|
||||||
utils.IncludeExchangeRestoreDataSelectors(sel, opts)
|
utils.IncludeExchangeRestoreDataSelectors(sel, opts)
|
||||||
utils.FilterExchangeRestoreInfoSelectors(sel, opts)
|
utils.FilterExchangeRestoreInfoSelectors(sel, opts)
|
||||||
@ -387,15 +413,7 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
|
|||||||
sel.Include(sel.Users(selectors.Any()))
|
sel.Include(sel.Users(selectors.Any()))
|
||||||
}
|
}
|
||||||
|
|
||||||
ds := sel.Reduce(ctx, d)
|
return sel.Reduce(ctx, d), nil
|
||||||
if len(ds.Entries) == 0 {
|
|
||||||
Info(ctx, selectors.ErrorNoMatchingItems)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ds.PrintEntries(ctx)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package backup
|
package backup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -9,6 +10,7 @@ import (
|
|||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/cli/utils"
|
"github.com/alcionai/corso/src/cli/utils"
|
||||||
|
"github.com/alcionai/corso/src/cli/utils/testdata"
|
||||||
"github.com/alcionai/corso/src/internal/tester"
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -214,3 +216,56 @@ func (suite *ExchangeSuite) TestExchangeBackupCreateSelectors() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *ExchangeSuite) TestExchangeBackupDetailsSelectors() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
for _, test := range testdata.ExchangeOptionDetailLookups {
|
||||||
|
suite.T().Run(test.Name, func(t *testing.T) {
|
||||||
|
output, err := runDetailsExchangeCmd(
|
||||||
|
ctx,
|
||||||
|
test.BackupGetter,
|
||||||
|
"backup-ID",
|
||||||
|
test.Opts,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.ElementsMatch(t, test.Expected, output.Entries)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *ExchangeSuite) TestExchangeBackupDetailsSelectorsBadBackupID() {
|
||||||
|
t := suite.T()
|
||||||
|
ctx := context.Background()
|
||||||
|
backupGetter := &testdata.MockBackupGetter{}
|
||||||
|
|
||||||
|
output, err := runDetailsExchangeCmd(
|
||||||
|
ctx,
|
||||||
|
backupGetter,
|
||||||
|
"backup-ID",
|
||||||
|
utils.ExchangeOpts{},
|
||||||
|
)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
|
assert.Empty(t, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(ashmrtn): Uncomment these when the CLI validates flag input values.
|
||||||
|
//func (suite *ExchangeSuite) TestExchangeBackupDetailsSelectorsBadFormats() {
|
||||||
|
// ctx := context.Background()
|
||||||
|
//
|
||||||
|
// for _, test := range testdata.BadExchangeOptionsFormats {
|
||||||
|
// suite.T().Run(test.Name, func(t *testing.T) {
|
||||||
|
// output, err := runDetailsExchangeCmd(
|
||||||
|
// ctx,
|
||||||
|
// test.BackupGetter,
|
||||||
|
// "backup-ID",
|
||||||
|
// test.Opts,
|
||||||
|
// )
|
||||||
|
// assert.Error(t, err)
|
||||||
|
//
|
||||||
|
// assert.Empty(t, output)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|||||||
181
src/cli/utils/testdata/opts.go
vendored
Normal file
181
src/cli/utils/testdata/opts.go
vendored
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
package testdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cli/utils"
|
||||||
|
"github.com/alcionai/corso/src/internal/common"
|
||||||
|
"github.com/alcionai/corso/src/internal/model"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup"
|
||||||
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
|
"github.com/alcionai/corso/src/pkg/selectors/testdata"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExchangeOptionsTest struct {
|
||||||
|
Name string
|
||||||
|
Opts utils.ExchangeOpts
|
||||||
|
BackupGetter *MockBackupGetter
|
||||||
|
Expected []details.DetailsEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
|
||||||
|
// BadExchangeOptionsFormats contains ExchangeOpts with flags that should
|
||||||
|
// cause errors about the format of the input flag. Mocks are configured to
|
||||||
|
// allow the system to run if it doesn't throw an error on formatting.
|
||||||
|
BadExchangeOptionsFormats = []ExchangeOptionsTest{
|
||||||
|
{
|
||||||
|
Name: "BadEmailReceiveAfter",
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EmailReceivedAfter: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "BadEmailReceiveBefore",
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EmailReceivedBefore: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "BadEventRecurs",
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EventRecurs: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "BadEventStartsAfter",
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EventStartsAfter: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "BadEventStartsBefore",
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EventStartsBefore: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExchangeOptionDetailLookups contains flag inputs and expected results for
|
||||||
|
// some choice input patterns. This set is not exhaustive. All inputs and
|
||||||
|
// outputs are according to the data laid out in selectors/testdata. Mocks are
|
||||||
|
// configured to return the full dataset listed in selectors/testdata.
|
||||||
|
ExchangeOptionDetailLookups = []ExchangeOptionsTest{
|
||||||
|
{
|
||||||
|
Name: "Emails",
|
||||||
|
Expected: testdata.ExchangeEmailItems,
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
Emails: selectors.Any(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "EmailsBySubject",
|
||||||
|
Expected: testdata.ExchangeEmailItems,
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EmailSender: "a-person",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "AllExchange",
|
||||||
|
Expected: append(
|
||||||
|
append(
|
||||||
|
append(
|
||||||
|
[]details.DetailsEntry{},
|
||||||
|
testdata.ExchangeEmailItems...,
|
||||||
|
),
|
||||||
|
testdata.ExchangeContactsItems...,
|
||||||
|
),
|
||||||
|
testdata.ExchangeEventsItems...,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "MailReceivedTime",
|
||||||
|
Expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EmailReceivedBefore: common.FormatTime(testdata.Time1.Add(time.Second)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "MailID",
|
||||||
|
Expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
Emails: []string{testdata.ExchangeEmailItemPath1.Item()},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "MailShortRef",
|
||||||
|
Expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
Emails: []string{testdata.ExchangeEmailItemPath1.ShortRef()},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "MultipleMailShortRef",
|
||||||
|
Expected: testdata.ExchangeEmailItems,
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
Emails: []string{
|
||||||
|
testdata.ExchangeEmailItemPath1.ShortRef(),
|
||||||
|
testdata.ExchangeEmailItemPath2.ShortRef(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "AllEventsAndMailWithSubject",
|
||||||
|
Expected: []details.DetailsEntry{testdata.ExchangeEmailItems[0]},
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EmailSubject: "foo",
|
||||||
|
Events: selectors.Any(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "EventsAndMailWithSubject",
|
||||||
|
Expected: []details.DetailsEntry{},
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
EmailSubject: "foo",
|
||||||
|
EventSubject: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "EventsAndMailByShortRef",
|
||||||
|
Expected: []details.DetailsEntry{
|
||||||
|
testdata.ExchangeEmailItems[0],
|
||||||
|
testdata.ExchangeEventsItems[0],
|
||||||
|
},
|
||||||
|
Opts: utils.ExchangeOpts{
|
||||||
|
Emails: []string{testdata.ExchangeEmailItemPath1.ShortRef()},
|
||||||
|
Events: []string{testdata.ExchangeEventsItemPath1.ShortRef()},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockBackupGetter implements the repo.BackupGetter interface and returns
|
||||||
|
// (selectors/testdata.GetDetailsSet(), nil, nil) when BackupDetails is called
|
||||||
|
// on the nil instance. If an instance is given or Backups is called returns an
|
||||||
|
// error.
|
||||||
|
type MockBackupGetter struct{}
|
||||||
|
|
||||||
|
func (MockBackupGetter) Backup(
|
||||||
|
context.Context,
|
||||||
|
model.StableID,
|
||||||
|
) (*backup.Backup, error) {
|
||||||
|
return nil, errors.New("unexpected call to mock")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (MockBackupGetter) Backups(context.Context) ([]backup.Backup, error) {
|
||||||
|
return nil, errors.New("unexpected call to mock")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bg *MockBackupGetter) BackupDetails(
|
||||||
|
ctx context.Context,
|
||||||
|
backupID string,
|
||||||
|
) (*details.Details, *backup.Backup, error) {
|
||||||
|
if bg == nil {
|
||||||
|
return testdata.GetDetailsSet(), nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil, errors.New("unexpected call to mock")
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user