From 192c69c68ff4881dceb9c65d6a617f34defc8ee2 Mon Sep 17 00:00:00 2001 From: Keepers Date: Fri, 12 Aug 2022 14:04:44 -0600 Subject: [PATCH] add backup cli integration test (#517) Adds the basic cli-based backup integration test. Due to discovering some corner cases about panic conditions and other error handling in bad runtime state, updates many other packages for safety. --- src/cli/backup/exchange_integration_test.go | 75 +++++++++++++++++++++ src/cli/config/account.go | 3 +- src/cli/config/config.go | 10 --- src/cli/config/storage.go | 7 +- src/cli/repo/s3_integration_test.go | 7 +- src/cmd/purge/purge.go | 12 +--- src/internal/common/slices.go | 10 +++ src/internal/operations/restore.go | 2 - src/internal/tester/integration_runners.go | 8 ++- 9 files changed, 99 insertions(+), 35 deletions(-) create mode 100644 src/cli/backup/exchange_integration_test.go diff --git a/src/cli/backup/exchange_integration_test.go b/src/cli/backup/exchange_integration_test.go new file mode 100644 index 000000000..0027d96ee --- /dev/null +++ b/src/cli/backup/exchange_integration_test.go @@ -0,0 +1,75 @@ +package backup_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + "github.com/alcionai/corso/cli" + "github.com/alcionai/corso/cli/config" + "github.com/alcionai/corso/internal/tester" + "github.com/alcionai/corso/pkg/repository" +) + +type ExchangeIntegrationSuite struct { + suite.Suite +} + +func TestExchangeIntegrationSuite(t *testing.T) { + if err := tester.RunOnAny( + tester.CorsoCITests, + tester.CorsoCLITests, + tester.CorsoCLIBackupTests, + ); err != nil { + t.Skip(err) + } + suite.Run(t, new(ExchangeIntegrationSuite)) +} + +func (suite *ExchangeIntegrationSuite) SetupSuite() { + _, err := tester.GetRequiredEnvVars( + append( + tester.AWSStorageCredEnvs, + tester.M365AcctCredEnvs..., + )..., + ) + require.NoError(suite.T(), err) +} + +func (suite *ExchangeIntegrationSuite) TestExchangeBackupCmd() { + ctx := tester.NewContext() + t := suite.T() + + acct := tester.NewM365Account(t) + st := tester.NewPrefixedS3Storage(t) + cfg, err := st.S3Config() + require.NoError(t, err) + + force := map[string]string{ + tester.TestCfgAccountProvider: "M365", + tester.TestCfgStorageProvider: "S3", + tester.TestCfgPrefix: cfg.Prefix, + } + vpr, configFP, err := tester.MakeTempTestConfigClone(t, force) + require.NoError(t, err) + ctx = config.SetViper(ctx, vpr) + + // init the repo first + _, err = repository.Initialize(ctx, acct, st) + require.NoError(t, err) + + m365UserID := tester.M365UserID(t) + + // then test it + cmd := tester.StubRootCmd( + "backup", "create", "exchange", + "--config-file", configFP, + "--user", m365UserID, + "--data", "email", + ) + cli.BuildCommandTree(cmd) + + // run the command + require.NoError(t, cmd.ExecuteContext(ctx)) +} diff --git a/src/cli/config/account.go b/src/cli/config/account.go index 98435e0dc..e604a869b 100644 --- a/src/cli/config/account.go +++ b/src/cli/config/account.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/viper" "github.com/alcionai/corso/cli/utils" + "github.com/alcionai/corso/internal/common" "github.com/alcionai/corso/pkg/account" "github.com/alcionai/corso/pkg/credentials" ) @@ -63,7 +64,7 @@ func configureAccount( m365Cfg = account.M365Config{ M365: m365, - TenantID: first(overrides[account.TenantID], m365Cfg.TenantID, os.Getenv(account.TenantID)), + TenantID: common.First(overrides[account.TenantID], m365Cfg.TenantID, os.Getenv(account.TenantID)), } // ensure required properties are present diff --git a/src/cli/config/config.go b/src/cli/config/config.go index 10d5d9485..7ff6c0e7f 100644 --- a/src/cli/config/config.go +++ b/src/cli/config/config.go @@ -220,16 +220,6 @@ func getStorageAndAccountWithViper( // Helper funcs // --------------------------------------------------------------------------- -// returns the first non-zero valued string -func first(vs ...string) string { - for _, v := range vs { - if len(v) > 0 { - return v - } - } - return "" -} - var constToTomlKeyMap = map[string]string{ account.TenantID: TenantIDKey, AccountProviderTypeKey: AccountProviderTypeKey, diff --git a/src/cli/config/storage.go b/src/cli/config/storage.go index 2729756de..cf7ddae08 100644 --- a/src/cli/config/storage.go +++ b/src/cli/config/storage.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/viper" "github.com/alcionai/corso/cli/utils" + "github.com/alcionai/corso/internal/common" "github.com/alcionai/corso/pkg/credentials" "github.com/alcionai/corso/pkg/storage" ) @@ -66,9 +67,9 @@ func configureStorage( s3Cfg = storage.S3Config{ AWS: aws, - Bucket: first(overrides[storage.Bucket], s3Cfg.Bucket, os.Getenv(storage.BucketKey)), - Endpoint: first(overrides[storage.Endpoint], s3Cfg.Endpoint, os.Getenv(storage.EndpointKey)), - Prefix: first(overrides[storage.Prefix], s3Cfg.Prefix, os.Getenv(storage.PrefixKey)), + Bucket: common.First(overrides[storage.Bucket], s3Cfg.Bucket, os.Getenv(storage.BucketKey)), + Endpoint: common.First(overrides[storage.Endpoint], s3Cfg.Endpoint, os.Getenv(storage.EndpointKey)), + Prefix: common.First(overrides[storage.Prefix], s3Cfg.Prefix, os.Getenv(storage.PrefixKey)), } // compose the common config and credentials diff --git a/src/cli/repo/s3_integration_test.go b/src/cli/repo/s3_integration_test.go index 9fe0b84e3..9e9dffcf2 100644 --- a/src/cli/repo/s3_integration_test.go +++ b/src/cli/repo/s3_integration_test.go @@ -13,10 +13,6 @@ import ( "github.com/alcionai/corso/pkg/repository" ) -// --------------------------------------------------------------------------------------------------------- -// Integration -// --------------------------------------------------------------------------------------------------------- - type S3IntegrationSuite struct { suite.Suite } @@ -24,6 +20,7 @@ type S3IntegrationSuite struct { func TestS3IntegrationSuite(t *testing.T) { if err := tester.RunOnAny( tester.CorsoCITests, + tester.CorsoCLITests, tester.CorsoCLIRepoTests, ); err != nil { t.Skip(err) @@ -104,7 +101,7 @@ func (suite *S3IntegrationSuite) TestConnectS3Cmd() { _, err = repository.Initialize(ctx, account.Account{}, st) require.NoError(t, err) - // then connect to it + // then test it cmd := tester.StubRootCmd( "repo", "connect", "s3", "--config-file", configFP, diff --git a/src/cmd/purge/purge.go b/src/cmd/purge/purge.go index 5b0156829..b72e8079f 100644 --- a/src/cmd/purge/purge.go +++ b/src/cmd/purge/purge.go @@ -37,7 +37,7 @@ func doFolderPurge(cmd *cobra.Command, args []string) error { // get account info m365Cfg := account.M365Config{ M365: credentials.GetM365(), - TenantID: first(tenant, os.Getenv(account.TenantID)), + TenantID: common.First(tenant, os.Getenv(account.TenantID)), } acct, err := account.NewAccount(account.ProviderM365, m365Cfg) if err != nil { @@ -110,13 +110,3 @@ func main() { os.Exit(1) } } - -// returns the first non-zero valued string -func first(vs ...string) string { - for _, v := range vs { - if len(v) > 0 { - return v - } - } - return "" -} diff --git a/src/internal/common/slices.go b/src/internal/common/slices.go index 2d8522981..50594edaa 100644 --- a/src/internal/common/slices.go +++ b/src/internal/common/slices.go @@ -8,3 +8,13 @@ func ContainsString(super []string, sub string) bool { } return false } + +// First returns the first non-zero valued string +func First(vs ...string) string { + for _, v := range vs { + if len(v) > 0 { + return v + } + } + return "" +} diff --git a/src/internal/operations/restore.go b/src/internal/operations/restore.go index b0acbaf56..284e91468 100644 --- a/src/internal/operations/restore.go +++ b/src/internal/operations/restore.go @@ -78,7 +78,6 @@ type restoreStats struct { } // Run begins a synchronous restore operation. -// todo (keepers): return stats block in first param. func (op *RestoreOperation) Run(ctx context.Context) (err error) { // TODO: persist initial state of restoreOperation in modelstore @@ -157,7 +156,6 @@ func (op *RestoreOperation) persistResults( op.Status = Completed if !opStats.started { - op.Status = Failed op.Status = Failed return multierror.Append( errors.New("errors prevented the operation from processing"), diff --git a/src/internal/tester/integration_runners.go b/src/internal/tester/integration_runners.go index e5ac580ed..f6bd5841a 100644 --- a/src/internal/tester/integration_runners.go +++ b/src/internal/tester/integration_runners.go @@ -10,8 +10,10 @@ import ( const ( CorsoCITests = "CORSO_CI_TESTS" - CorsoCLIConfigTests = "CORSO_CLI_CONFIG_TESTS" - CorsoCLIRepoTests = "CORSO_CLI_REPO_TESTS" + CorsoCLIBackupTests = "CORSO_COMMAND_LINE_BACKUP_TESTS" + CorsoCLIConfigTests = "CORSO_COMMAND_LINE_CONFIG_TESTS" + CorsoCLIRepoTests = "CORSO_COMMAND_LINE_REPO_TESTS" + CorsoCLITests = "CORSO_COMMAND_LINE_TESTS" CorsoGraphConnectorTests = "CORSO_GRAPH_CONNECTOR_TESTS" CorsoKopiaWrapperTests = "CORSO_KOPIA_WRAPPER_TESTS" CorsoModelStoreTests = "CORSO_MODEL_STORE_TESTS" @@ -42,7 +44,7 @@ func RunOnAny(tests ...string) error { // LogTimeOfTest logs the test name and the time that it was run. func LogTimeOfTest(t *testing.T) string { - now := time.Now().UTC().Format("2006-01-02T15:04:05.0000") + now := time.Now().UTC().Format(time.RFC3339Nano) name := t.Name() if name == "" { t.Logf("Test run at %s.", now)