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.
This commit is contained in:
Keepers 2022-08-12 14:04:44 -06:00 committed by GitHub
parent 6464a66b46
commit 192c69c68f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 99 additions and 35 deletions

View File

@ -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))
}

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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 ""
}

View File

@ -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 ""
}

View File

@ -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"),

View File

@ -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)