From 09cc2769d9cf1c34df9c6c3e0db5f7d2b9cdb63c Mon Sep 17 00:00:00 2001 From: ashmrtn <3891298+ashmrtn@users.noreply.github.com> Date: Fri, 26 Aug 2022 10:58:58 -0700 Subject: [PATCH] Fix most remaining wsl lint errors (#656) * Fix wsl lint errors in pkg package * Fix wsl lint errors in most of internal package Leave some sub-packages out that have higher churn at the moment. --- src/internal/common/configs.go | 3 ++ src/internal/common/errors.go | 2 ++ src/internal/common/errors_test.go | 10 ++++-- src/internal/common/slices.go | 2 ++ src/internal/common/slices_test.go | 1 + src/internal/common/time.go | 3 ++ src/internal/operations/backup.go | 19 +++++++----- src/internal/operations/backup_test.go | 2 +- src/internal/operations/operation.go | 2 ++ src/internal/operations/operation_test.go | 1 + src/internal/operations/restore.go | 14 +++++++-- src/internal/operations/restore_test.go | 6 ++++ src/internal/tester/account.go | 1 + src/internal/tester/cli.go | 1 + src/internal/tester/config.go | 11 +++++-- src/internal/tester/envvars.go | 6 ++++ src/internal/tester/envvars_test.go | 2 ++ src/internal/tester/integration_runners.go | 5 +++ src/internal/tester/loader.go | 6 ++++ src/internal/tester/storage.go | 2 ++ src/internal/tester/users.go | 1 + src/pkg/account/account.go | 1 + src/pkg/account/m365.go | 4 +++ src/pkg/backup/backup.go | 2 ++ src/pkg/backup/backup_test.go | 4 ++- src/pkg/backup/details/details.go | 11 +++++++ src/pkg/control/options_test.go | 2 ++ src/pkg/credentials/aws.go | 3 ++ src/pkg/credentials/corso.go | 3 ++ src/pkg/credentials/m365.go | 2 ++ src/pkg/filters/filters.go | 3 ++ src/pkg/logger/logger.go | 7 +++++ src/pkg/repository/repository.go | 6 ++++ src/pkg/repository/repository_test.go | 1 + src/pkg/selectors/exchange.go | 36 ++++++++++++++++++++++ src/pkg/selectors/exchange_test.go | 31 ++++++++++++++++++- src/pkg/selectors/helpers_test.go | 4 +++ src/pkg/selectors/onedrive.go | 10 ++++++ src/pkg/selectors/onedrive_test.go | 2 ++ src/pkg/selectors/scopes.go | 17 ++++++++++ src/pkg/selectors/scopes_test.go | 5 +++ src/pkg/selectors/selectors.go | 22 ++++++++++++- src/pkg/selectors/selectors_test.go | 1 + src/pkg/storage/common.go | 4 +++ src/pkg/storage/s3.go | 4 +++ src/pkg/storage/storage.go | 3 ++ src/pkg/store/backup.go | 11 +++++++ src/pkg/store/mock/store_mock.go | 10 ++++++ 48 files changed, 289 insertions(+), 20 deletions(-) diff --git a/src/internal/common/configs.go b/src/internal/common/configs.go index ce232c2c0..73e6c2630 100644 --- a/src/internal/common/configs.go +++ b/src/internal/common/configs.go @@ -8,14 +8,17 @@ type StringConfigurer interface { // map[string]string matching type. func UnionStringConfigs(cfgs ...StringConfigurer) (map[string]string, error) { union := map[string]string{} + for _, cfg := range cfgs { c, err := cfg.StringConfig() if err != nil { return nil, err } + for k, v := range c { union[k] = v } } + return union, nil } diff --git a/src/internal/common/errors.go b/src/internal/common/errors.go index bee77ff0f..2eb3ba891 100644 --- a/src/internal/common/errors.go +++ b/src/internal/common/errors.go @@ -43,6 +43,7 @@ func (e Err) Format(s fmt.State, verb rune) { f.Format(s, verb) return } + // Formatting magic courtesy of github.com/pkg/errors. switch verb { case 'v': @@ -50,6 +51,7 @@ func (e Err) Format(s fmt.State, verb rune) { fmt.Fprintf(s, "%+v\n", e.Cause()) return } + fallthrough case 's', 'q': // nolint:errcheck diff --git a/src/internal/common/errors_test.go b/src/internal/common/errors_test.go index 53ed89400..bcc3e3c8a 100644 --- a/src/internal/common/errors_test.go +++ b/src/internal/common/errors_test.go @@ -39,6 +39,7 @@ func (suite *ErrorsUnitSuite) TestPropagatesIs() { err := assert.AnError te := testErr{*common.EncapsulateError(err)} te2 := testErr2{*common.EncapsulateError(te)} + assert.True(suite.T(), errors.Is(te2, err)) } @@ -46,7 +47,8 @@ func (suite *ErrorsUnitSuite) TestPropagatesAs() { err := assert.AnError te := testErr{*common.EncapsulateError(err)} te2 := testErr2{*common.EncapsulateError(te)} - var tmp testErr + + tmp := testErr{} assert.True(suite.T(), errors.As(te2, &tmp)) } @@ -54,14 +56,16 @@ func (suite *ErrorsUnitSuite) TestAs() { err := assert.AnError te := testErr{*common.EncapsulateError(err)} te2 := testErr2{*common.EncapsulateError(te)} - var tmp testErr2 + + tmp := testErr2{} assert.True(suite.T(), errors.As(te2, &tmp)) } func (suite *ErrorsUnitSuite) TestAsIsUnique() { err := assert.AnError te := testErr{*common.EncapsulateError(err)} - var tmp testErr2 + + tmp := testErr2{} assert.False(suite.T(), errors.As(te, &tmp)) } diff --git a/src/internal/common/slices.go b/src/internal/common/slices.go index 50594edaa..7600400e9 100644 --- a/src/internal/common/slices.go +++ b/src/internal/common/slices.go @@ -6,6 +6,7 @@ func ContainsString(super []string, sub string) bool { return true } } + return false } @@ -16,5 +17,6 @@ func First(vs ...string) string { return v } } + return "" } diff --git a/src/internal/common/slices_test.go b/src/internal/common/slices_test.go index 63e4fc986..debd5928c 100644 --- a/src/internal/common/slices_test.go +++ b/src/internal/common/slices_test.go @@ -22,6 +22,7 @@ func (suite *CommonSlicesSuite) TestContainsString() { target := "fnords" good := []string{"fnords"} bad := []string{"foo", "bar"} + assert.True(t, common.ContainsString(good, target)) assert.False(t, common.ContainsString(bad, target)) } diff --git a/src/internal/common/time.go b/src/internal/common/time.go index aa6777f68..424241293 100644 --- a/src/internal/common/time.go +++ b/src/internal/common/time.go @@ -34,13 +34,16 @@ func ParseTime(s string) (time.Time, error) { if len(s) == 0 { return time.Time{}, errors.New("cannot interpret an empty string as time.Time") } + t, err := time.Parse(StandardTimeFormat, s) if err == nil { return t.UTC(), nil } + t, err = time.Parse(SimpleDateTimeFormat, s) if err == nil { return t.UTC(), nil } + return time.Time{}, errors.New("unable to format time string: " + s) } diff --git a/src/internal/operations/backup.go b/src/internal/operations/backup.go index 62b636f7a..136b35eb0 100644 --- a/src/internal/operations/backup.go +++ b/src/internal/operations/backup.go @@ -9,7 +9,6 @@ import ( "github.com/alcionai/corso/internal/connector" "github.com/alcionai/corso/internal/connector/support" - "github.com/alcionai/corso/internal/data" "github.com/alcionai/corso/internal/kopia" "github.com/alcionai/corso/internal/model" "github.com/alcionai/corso/internal/stats" @@ -78,13 +77,13 @@ type backupStats struct { // Run begins a synchronous backup operation. func (op *BackupOperation) Run(ctx context.Context) (err error) { - // TODO: persist initial state of backupOperation in modelstore - - // persist operation results to the model store on exit var ( opStats backupStats backupDetails *details.Details ) + // TODO: persist initial state of backupOperation in modelstore + + // persist operation results to the model store on exit defer func() { err = op.persistResults(time.Now(), &opStats) if err != nil { @@ -93,8 +92,8 @@ func (op *BackupOperation) Run(ctx context.Context) (err error) { err = op.createBackupModels(ctx, opStats.k.SnapshotID, backupDetails) if err != nil { + // todo: we're not persisting this yet, except for the error shown to the user. opStats.writeErr = err - // todo: ^ we're not persisting this yet, except for the error shown to the user. } }() @@ -103,14 +102,15 @@ func (op *BackupOperation) Run(ctx context.Context) (err error) { if err != nil { err = errors.Wrap(err, "connecting to graph api") opStats.readErr = err + return err } - var cs []data.Collection - cs, err = gc.ExchangeDataCollection(ctx, op.Selectors) + cs, err := gc.ExchangeDataCollection(ctx, op.Selectors) if err != nil { err = errors.Wrap(err, "retrieving service data") opStats.readErr = err + return err } @@ -119,8 +119,10 @@ func (op *BackupOperation) Run(ctx context.Context) (err error) { if err != nil { err = errors.Wrap(err, "backing up service data") opStats.writeErr = err + return err } + opStats.started = true opStats.gc = gc.AwaitStatus() @@ -139,6 +141,7 @@ func (op *BackupOperation) persistResults( op.Status = Completed if !opStats.started { op.Status = Failed + return multierror.Append( errors.New("errors prevented the operation from processing"), opStats.readErr, @@ -174,10 +177,12 @@ func (op *BackupOperation) createBackupModels( op.Results.ReadWrites, op.Results.StartAndEndTime, ) + err = op.store.Put(ctx, model.BackupSchema, b) if err != nil { return errors.Wrap(err, "creating backup model") } + op.Results.BackupID = b.ID return nil diff --git a/src/internal/operations/backup_test.go b/src/internal/operations/backup_test.go index 9bca9ee4c..16ad4459c 100644 --- a/src/internal/operations/backup_test.go +++ b/src/internal/operations/backup_test.go @@ -82,6 +82,7 @@ func TestBackupOpIntegrationSuite(t *testing.T) { ); err != nil { t.Skip(err) } + suite.Run(t, new(BackupOpIntegrationSuite)) } @@ -164,7 +165,6 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run() { }, }, } - for _, test := range tests { suite.T().Run(test.name, func(t *testing.T) { // need to initialize the repository before we can test connecting to it. diff --git a/src/internal/operations/operation.go b/src/internal/operations/operation.go index 90e68301c..d66b00c51 100644 --- a/src/internal/operations/operation.go +++ b/src/internal/operations/operation.go @@ -63,8 +63,10 @@ func (op operation) validate() error { if op.kopia == nil { return errors.New("missing kopia connection") } + if op.store == nil { return errors.New("missing modelstore") } + return nil } diff --git a/src/internal/operations/operation_test.go b/src/internal/operations/operation_test.go index 0b44effb8..59b721a92 100644 --- a/src/internal/operations/operation_test.go +++ b/src/internal/operations/operation_test.go @@ -29,6 +29,7 @@ func (suite *OperationSuite) TestNewOperation() { func (suite *OperationSuite) TestOperation_Validate() { kwStub := &kopia.Wrapper{} swStub := &store.Wrapper{} + table := []struct { name string kw *kopia.Wrapper diff --git a/src/internal/operations/restore.go b/src/internal/operations/restore.go index dbfcc0581..aa07e51af 100644 --- a/src/internal/operations/restore.go +++ b/src/internal/operations/restore.go @@ -81,16 +81,14 @@ type restoreStats struct { // Run begins a synchronous restore operation. func (op *RestoreOperation) Run(ctx context.Context) (err error) { // TODO: persist initial state of restoreOperation in modelstore - // persist operation results to the model store on exit opStats := restoreStats{} + // TODO: persist results? defer func() { err = op.persistResults(time.Now(), &opStats) if err != nil { return } - - // TODO: persist results? }() // retrieve the restore point details @@ -98,6 +96,7 @@ func (op *RestoreOperation) Run(ctx context.Context) (err error) { if err != nil { err = errors.Wrap(err, "getting backup details for restore") opStats.readErr = err + return err } @@ -116,15 +115,19 @@ func (op *RestoreOperation) Run(ctx context.Context) (err error) { // todo: use path pkg for this fdsPaths := fds.Paths() paths := make([][]string, len(fdsPaths)) + for i := range fdsPaths { paths[i] = strings.Split(fdsPaths[i], "/") } + dcs, err := op.kopia.RestoreMultipleItems(ctx, b.SnapshotID, paths) if err != nil { err = errors.Wrap(err, "retrieving service data") opStats.readErr = err + return err } + opStats.cs = dcs // restore those collections using graph @@ -132,6 +135,7 @@ func (op *RestoreOperation) Run(ctx context.Context) (err error) { if err != nil { err = errors.Wrap(err, "connecting to graph api") opStats.writeErr = err + return err } @@ -139,8 +143,10 @@ func (op *RestoreOperation) Run(ctx context.Context) (err error) { if err != nil { err = errors.Wrap(err, "restoring service data") opStats.writeErr = err + return err } + opStats.started = true opStats.gc = gc.AwaitStatus() logger.Ctx(ctx).Debug(gc.PrintableStatus()) @@ -157,8 +163,10 @@ func (op *RestoreOperation) persistResults( op.Results.CompletedAt = time.Now() op.Status = Completed + if !opStats.started { op.Status = Failed + return multierror.Append( errors.New("errors prevented the operation from processing"), opStats.readErr, diff --git a/src/internal/operations/restore_test.go b/src/internal/operations/restore_test.go index 2fb8c59c7..98ad4aca9 100644 --- a/src/internal/operations/restore_test.go +++ b/src/internal/operations/restore_test.go @@ -92,6 +92,7 @@ func TestRestoreOpIntegrationSuite(t *testing.T) { ); err != nil { t.Skip(err) } + suite.Run(t, new(RestoreOpIntegrationSuite)) } @@ -110,16 +111,19 @@ func (suite *RestoreOpIntegrationSuite) SetupSuite() { k := kopia.NewConn(st) require.NoError(t, k.Initialize(ctx)) + suite.kopiaCloser = func(ctx context.Context) { k.Close(ctx) } kw, err := kopia.NewWrapper(k) require.NoError(t, err) + suite.kw = kw ms, err := kopia.NewModelStore(k) require.NoError(t, err) + suite.ms = ms sw := store.NewKopiaStore(ms) @@ -148,9 +152,11 @@ func (suite *RestoreOpIntegrationSuite) TearDownSuite() { if suite.ms != nil { suite.ms.Close(ctx) } + if suite.kw != nil { suite.kw.Close(ctx) } + if suite.kopiaCloser != nil { suite.kopiaCloser(ctx) } diff --git a/src/internal/tester/account.go b/src/internal/tester/account.go index eb6e2ae4e..b5b75e636 100644 --- a/src/internal/tester/account.go +++ b/src/internal/tester/account.go @@ -28,5 +28,6 @@ func NewM365Account(t *testing.T) account.Account { }, ) require.NoError(t, err, "initializing account") + return acc } diff --git a/src/internal/tester/cli.go b/src/internal/tester/cli.go index 7c4313b71..842948d37 100644 --- a/src/internal/tester/cli.go +++ b/src/internal/tester/cli.go @@ -27,6 +27,7 @@ func StubRootCmd(args ...string) *cobra.Command { }, } c.SetArgs(args) + return c } diff --git a/src/internal/tester/config.go b/src/internal/tester/config.go index b63c97107..5a9bc286a 100644 --- a/src/internal/tester/config.go +++ b/src/internal/tester/config.go @@ -39,10 +39,12 @@ func cloneTestConfig() map[string]string { if testConfig == nil { return map[string]string{} } + clone := map[string]string{} for k, v := range testConfig { clone[k] = v } + return clone } @@ -55,7 +57,6 @@ func NewTestViper() (*viper.Viper, error) { } // Or use a custom file location - fileName := path.Base(configFilePath) ext := path.Ext(configFilePath) if len(ext) == 0 { return nil, errors.New("corso_test requires an extension") @@ -64,6 +65,8 @@ func NewTestViper() (*viper.Viper, error) { vpr.SetConfigFile(configFilePath) vpr.AddConfigPath(path.Dir(configFilePath)) vpr.SetConfigType(ext[1:]) + + fileName := path.Base(configFilePath) fileName = strings.TrimSuffix(fileName, ext) vpr.SetConfigName(fileName) @@ -105,9 +108,10 @@ func readTestConfig() (map[string]string, error) { vpr.GetString(TestCfgUserID), "lidiah@8qzvrj.onmicrosoft.com", ) - testEnv[EnvCorsoTestConfigFilePath] = os.Getenv(EnvCorsoTestConfigFilePath) + testEnv[EnvCorsoTestConfigFilePath] = os.Getenv(EnvCorsoTestConfigFilePath) testConfig = testEnv + return cloneTestConfig(), nil } @@ -130,6 +134,7 @@ func MakeTempTestConfigClone(t *testing.T, overrides map[string]string) (*viper. if len(fName) == 0 || fName == "." || fName == "/" { fName = ".corso_test.toml" } + tDir := t.TempDir() tDirFp := path.Join(tDir, fName) @@ -137,8 +142,8 @@ func MakeTempTestConfigClone(t *testing.T, overrides map[string]string) (*viper. return nil, "", err } - vpr := viper.New() ext := path.Ext(fName) + vpr := viper.New() vpr.SetConfigFile(tDirFp) vpr.AddConfigPath(tDir) vpr.SetConfigType(strings.TrimPrefix(ext, ".")) diff --git a/src/internal/tester/envvars.go b/src/internal/tester/envvars.go index fe8adc858..12a11cb2b 100644 --- a/src/internal/tester/envvars.go +++ b/src/internal/tester/envvars.go @@ -10,13 +10,16 @@ import ( // If any of the env values are zero length, returns an error. func GetRequiredEnvVars(evs ...string) (map[string]string, error) { vals := map[string]string{} + for _, ev := range evs { ge := os.Getenv(ev) if len(ge) == 0 { return nil, errors.New(ev + " env var required for test suite") } + vals[ev] = ge } + return vals, nil } @@ -25,14 +28,17 @@ func GetRequiredEnvVars(evs ...string) (map[string]string, error) { // If any of the env values are zero length, returns an error. func GetRequiredEnvSls(evs ...[]string) (map[string]string, error) { vals := map[string]string{} + for _, ev := range evs { r, err := GetRequiredEnvVars(ev...) if err != nil { return nil, err } + for k, v := range r { vals[k] = v } } + return vals, nil } diff --git a/src/internal/tester/envvars_test.go b/src/internal/tester/envvars_test.go index 90de9c097..b5205bffa 100644 --- a/src/internal/tester/envvars_test.go +++ b/src/internal/tester/envvars_test.go @@ -19,6 +19,7 @@ func TestEnvvarsSuite(t *testing.T) { func (suite *EnvvarsTestSuite) TestRunOnAny() { envVariable := "TEST_ENVVARS_SUITE" os.Setenv(envVariable, "1") + table := []struct { name string param string @@ -41,5 +42,6 @@ func (suite *EnvvarsTestSuite) TestRunOnAny() { test.function(suite.T(), result) }) } + os.Unsetenv(envVariable) } diff --git a/src/internal/tester/integration_runners.go b/src/internal/tester/integration_runners.go index 0ded45d7f..c2781d6ee 100644 --- a/src/internal/tester/integration_runners.go +++ b/src/internal/tester/integration_runners.go @@ -35,11 +35,13 @@ func RunOnAny(tests ...string) error { for _, test := range tests { l += len(os.Getenv(test)) } + if l == 0 { return fmt.Errorf( "%s env vars are not flagged for testing", strings.Join(tests, ", ")) } + return nil } @@ -47,10 +49,13 @@ func RunOnAny(tests ...string) error { func LogTimeOfTest(t *testing.T) string { now := time.Now().UTC().Format(time.RFC3339Nano) name := t.Name() + if name == "" { t.Logf("Test run at %s.", now) return now } + t.Logf("%s run at %s", name, now) + return now } diff --git a/src/internal/tester/loader.go b/src/internal/tester/loader.go index ff67f601c..26fd621fc 100644 --- a/src/internal/tester/loader.go +++ b/src/internal/tester/loader.go @@ -13,18 +13,24 @@ func LoadAFile(aFile string) ([]byte, error) { if err != nil { return nil, err } + defer f.Close() + buffer := make([]byte, 0) reader := bufio.NewScanner(f) + for reader.Scan() { temp := reader.Bytes() buffer = append(buffer, temp...) } + aErr := reader.Err() if aErr != nil { return nil, aErr } + return buffer, nil } + return bytes, nil } diff --git a/src/internal/tester/storage.go b/src/internal/tester/storage.go index 5756f1449..fb134cc15 100644 --- a/src/internal/tester/storage.go +++ b/src/internal/tester/storage.go @@ -23,6 +23,7 @@ var AWSStorageCredEnvs = []string{ // configs. func NewPrefixedS3Storage(t *testing.T) storage.Storage { now := LogTimeOfTest(t) + cfg, err := readTestConfig() require.NoError(t, err, "configuring storage from test file") @@ -39,5 +40,6 @@ func NewPrefixedS3Storage(t *testing.T) storage.Storage { }, ) require.NoError(t, err, "creating storage") + return st } diff --git a/src/internal/tester/users.go b/src/internal/tester/users.go index 80359b69a..eb764e1a1 100644 --- a/src/internal/tester/users.go +++ b/src/internal/tester/users.go @@ -13,5 +13,6 @@ import ( func M365UserID(t *testing.T) string { cfg, err := readTestConfig() require.NoError(t, err, "retrieving m365 user id from test configuration") + return cfg[TestCfgUserID] } diff --git a/src/pkg/account/account.go b/src/pkg/account/account.go index a1ffb907c..264b8dcd5 100644 --- a/src/pkg/account/account.go +++ b/src/pkg/account/account.go @@ -29,6 +29,7 @@ type Account struct { // NewAccount aggregates all the supplied configurations into a single configuration func NewAccount(p accountProvider, cfgs ...common.StringConfigurer) (Account, error) { cs, err := common.UnionStringConfigs(cfgs...) + return Account{ Provider: p, Config: cs, diff --git a/src/pkg/account/m365.go b/src/pkg/account/m365.go index e731de139..660d1e348 100644 --- a/src/pkg/account/m365.go +++ b/src/pkg/account/m365.go @@ -32,6 +32,7 @@ func (c M365Config) StringConfig() (map[string]string, error) { keyM365ClientSecret: c.ClientSecret, keyM365TenantID: c.TenantID, } + return cfg, c.validate() } @@ -43,6 +44,7 @@ func (a Account) M365Config() (M365Config, error) { c.ClientSecret = a.Config[keyM365ClientSecret] c.TenantID = a.Config[keyM365TenantID] } + return c, c.validate() } @@ -52,10 +54,12 @@ func (c M365Config) validate() error { credentials.ClientSecret: c.ClientSecret, TenantID: c.TenantID, } + for k, v := range check { if len(v) == 0 { return errors.Wrap(errMissingRequired, k) } } + return nil } diff --git a/src/pkg/backup/backup.go b/src/pkg/backup/backup.go index 1c6ae0710..5322f3515 100644 --- a/src/pkg/backup/backup.go +++ b/src/pkg/backup/backup.go @@ -71,6 +71,7 @@ func PrintAll(ctx context.Context, bs []Backup) { for _, b := range bs { ps = append(ps, print.Printable(b)) } + print.All(ctx, ps...) } @@ -111,6 +112,7 @@ func (b Backup) Headers() []string { func (b Backup) Values() []string { errCount := support.GetNumberOfErrors(b.ReadErrors) + support.GetNumberOfErrors(b.WriteErrors) status := fmt.Sprintf("%s (%d errors)", b.Status, errCount) + return []string{ common.FormatTime(b.StartedAt), string(b.ID), diff --git a/src/pkg/backup/backup_test.go b/src/pkg/backup/backup_test.go index 3d34fec50..daccffd30 100644 --- a/src/pkg/backup/backup_test.go +++ b/src/pkg/backup/backup_test.go @@ -27,6 +27,7 @@ func TestBackupSuite(t *testing.T) { func stubBackup(t time.Time) backup.Backup { sel := selectors.NewExchangeBackup() sel.Include(sel.Users(selectors.Any())) + return backup.Backup{ BaseModel: model.BaseModel{ ID: model.StableID("id"), @@ -62,14 +63,15 @@ func (suite *BackupSuite) TestBackup_HeadersValues() { } hs := b.Headers() assert.Equal(t, expectHs, hs) - nowFmt := common.FormatTime(now) + nowFmt := common.FormatTime(now) expectVs := []string{ nowFmt, "id", "status (2 errors)", selectors.All, } + vs := b.Values() assert.Equal(t, expectVs, vs) } diff --git a/src/pkg/backup/details/details.go b/src/pkg/backup/details/details.go index 3a9c95b46..9459fabed 100644 --- a/src/pkg/backup/details/details.go +++ b/src/pkg/backup/details/details.go @@ -26,6 +26,7 @@ func (dm DetailsModel) PrintEntries(ctx context.Context) { for _, de := range dm.Entries { ps = append(ps, de) } + print.All(ctx, ps...) } @@ -33,9 +34,11 @@ func (dm DetailsModel) PrintEntries(ctx context.Context) { func (dm DetailsModel) Paths() []string { ents := dm.Entries r := make([]string, len(ents)) + for i := range ents { r[i] = ents[i].RepoRef } + return r } @@ -88,30 +91,38 @@ func (de DetailsEntry) MinimumPrintable() any { // for printing out to a terminal in a columnar display. func (de DetailsEntry) Headers() []string { hs := []string{"Repo Ref"} + if de.ItemInfo.Exchange != nil { hs = append(hs, de.ItemInfo.Exchange.Headers()...) } + if de.ItemInfo.Sharepoint != nil { hs = append(hs, de.ItemInfo.Sharepoint.Headers()...) } + if de.ItemInfo.OneDrive != nil { hs = append(hs, de.ItemInfo.OneDrive.Headers()...) } + return hs } // Values returns the values matching the Headers list. func (de DetailsEntry) Values() []string { vs := []string{de.RepoRef} + if de.ItemInfo.Exchange != nil { vs = append(vs, de.ItemInfo.Exchange.Values()...) } + if de.ItemInfo.Sharepoint != nil { vs = append(vs, de.ItemInfo.Sharepoint.Values()...) } + if de.ItemInfo.OneDrive != nil { vs = append(vs, de.ItemInfo.OneDrive.Values()...) } + return vs } diff --git a/src/pkg/control/options_test.go b/src/pkg/control/options_test.go index f13eb3539..b04bff045 100644 --- a/src/pkg/control/options_test.go +++ b/src/pkg/control/options_test.go @@ -19,8 +19,10 @@ func TestOptionsSuite(t *testing.T) { func (suite *OptionsSuite) TestNewOptions() { t := suite.T() + o1 := control.NewOptions(true) assert.True(t, o1.FailFast, "failFast") + o2 := control.NewOptions(false) assert.False(t, o2.FailFast, "failFast") } diff --git a/src/pkg/credentials/aws.go b/src/pkg/credentials/aws.go index 16c946bba..61c0673aa 100644 --- a/src/pkg/credentials/aws.go +++ b/src/pkg/credentials/aws.go @@ -26,6 +26,7 @@ func GetAWS(override map[string]string) AWS { if ovr, ok := override[AWSAccessKeyID]; ok && ovr != "" { accessKey = ovr } + secretKey := os.Getenv(AWSSecretAccessKey) sessToken := os.Getenv(AWSSessionToken) @@ -44,10 +45,12 @@ func (c AWS) Validate() error { AWSSecretAccessKey: c.SecretKey, AWSSessionToken: c.SessionToken, } + for k, v := range check { if len(v) == 0 { return errors.Wrap(errMissingRequired, k) } } + return nil } diff --git a/src/pkg/credentials/corso.go b/src/pkg/credentials/corso.go index 9449c37a3..ad9d6d90f 100644 --- a/src/pkg/credentials/corso.go +++ b/src/pkg/credentials/corso.go @@ -21,6 +21,7 @@ func GetCorso() Corso { // todo (rkeeprs): read from either corso config file or env vars. // https://github.com/alcionai/corso/issues/120 corsoPasswd := os.Getenv(CorsoPassword) + return Corso{ CorsoPassword: corsoPasswd, } @@ -30,10 +31,12 @@ func (c Corso) Validate() error { check := map[string]string{ CorsoPassword: c.CorsoPassword, } + for k, v := range check { if len(v) == 0 { return errors.Wrap(errMissingRequired, k) } } + return nil } diff --git a/src/pkg/credentials/m365.go b/src/pkg/credentials/m365.go index 7710d8a71..c0652c67b 100644 --- a/src/pkg/credentials/m365.go +++ b/src/pkg/credentials/m365.go @@ -33,10 +33,12 @@ func (c M365) Validate() error { ClientID: c.ClientID, ClientSecret: c.ClientSecret, } + for k, v := range check { if len(v) == 0 { return errors.Wrap(errMissingRequired, k) } } + return nil } diff --git a/src/pkg/filters/filters.go b/src/pkg/filters/filters.go index 0d62199e6..d6ff0821e 100644 --- a/src/pkg/filters/filters.go +++ b/src/pkg/filters/filters.go @@ -83,6 +83,7 @@ func NewIn(negate bool, category any, substr string) Filter { // Checks whether the filter matches the input func (f Filter) Matches(input string) bool { var cmp func(string, string) bool + switch f.Comparator { case Equal: cmp = equals @@ -97,10 +98,12 @@ func (f Filter) Matches(input string) bool { case In: cmp = in } + result := cmp(f.Target, norm(input)) if f.Negate { result = !result } + return result } diff --git a/src/pkg/logger/logger.go b/src/pkg/logger/logger.go index fccae7960..0dd339d9f 100644 --- a/src/pkg/logger/logger.go +++ b/src/pkg/logger/logger.go @@ -68,14 +68,17 @@ func singleton(level logLevel) *zap.SugaredLogger { lgr *zap.Logger err error ) + if level != Production { cfg := zap.NewDevelopmentConfig() + switch level { case Info: cfg.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel) case Warn: cfg.Level = zap.NewAtomicLevelAt(zapcore.WarnLevel) } + lgr, err = cfg.Build() } else { lgr, err = zap.NewProduction() @@ -87,6 +90,7 @@ func singleton(level logLevel) *zap.SugaredLogger { } loggerton = lgr.Sugar() + return loggerton } @@ -126,6 +130,7 @@ func Seed(ctx context.Context) (ctxOut context.Context, zsl *zap.SugaredLogger) } level = levelOf(levelString) + return // return values handled in defer } @@ -135,6 +140,7 @@ func Ctx(ctx context.Context) *zap.SugaredLogger { if l == nil { return singleton(levelOf(llFlag)) } + return l.(*zap.SugaredLogger) } @@ -148,5 +154,6 @@ func levelOf(lvl string) logLevel { case "error": return Production } + return Info } diff --git a/src/pkg/repository/repository.go b/src/pkg/repository/repository.go index caa8244e8..7aaa9d813 100644 --- a/src/pkg/repository/repository.go +++ b/src/pkg/repository/repository.go @@ -70,6 +70,7 @@ func Initialize( dataLayer: w, modelStore: ms, } + return &r, nil } @@ -109,6 +110,7 @@ func Connect( dataLayer: w, modelStore: ms, } + return &r, nil } @@ -116,6 +118,7 @@ func (r *Repository) Close(ctx context.Context) error { if r.dataLayer != nil { err := r.dataLayer.Close(ctx) r.dataLayer = nil + if err != nil { return errors.Wrap(err, "closing corso DataLayer") } @@ -124,8 +127,10 @@ func (r *Repository) Close(ctx context.Context) error { if r.modelStore == nil { return nil } + err := r.modelStore.Close(ctx) r.modelStore = nil + return errors.Wrap(err, "closing corso ModelStore") } @@ -191,5 +196,6 @@ func (r Repository) DeleteBackup(ctx context.Context, id model.StableID) error { } sw := store.NewKopiaStore(r.modelStore) + return sw.DeleteBackup(ctx, id) } diff --git a/src/pkg/repository/repository_test.go b/src/pkg/repository/repository_test.go index 1afe48d7c..63ae7a08c 100644 --- a/src/pkg/repository/repository_test.go +++ b/src/pkg/repository/repository_test.go @@ -97,6 +97,7 @@ func TestRepositoryIntegrationSuite(t *testing.T) { ); err != nil { t.Skip(err) } + suite.Run(t, new(RepositoryIntegrationSuite)) } diff --git a/src/pkg/selectors/exchange.go b/src/pkg/selectors/exchange.go index 16400856d..01bddbe31 100644 --- a/src/pkg/selectors/exchange.go +++ b/src/pkg/selectors/exchange.go @@ -40,6 +40,7 @@ func NewExchangeBackup() *ExchangeBackup { newSelector(ServiceExchange), }, } + return &src } @@ -49,7 +50,9 @@ func (s Selector) ToExchangeBackup() (*ExchangeBackup, error) { if s.Service != ServiceExchange { return nil, badCastErr(ServiceExchange, s.Service) } + src := ExchangeBackup{exchange{s}} + return &src, nil } @@ -60,6 +63,7 @@ func NewExchangeRestore() *ExchangeRestore { newSelector(ServiceExchange), }, } + return &src } @@ -69,7 +73,9 @@ func (s Selector) ToExchangeRestore() (*ExchangeRestore, error) { if s.Service != ServiceExchange { return nil, badCastErr(ServiceExchange, s.Service) } + src := ExchangeRestore{exchange{s}} + return &src, nil } @@ -163,6 +169,7 @@ func (s *exchange) Contacts(users, folders, contacts []string) []ExchangeScope { folders = normalize(folders) contacts = normalize(contacts) scopes := []ExchangeScope{} + for _, u := range users { for _, f := range folders { scopes = append( @@ -171,6 +178,7 @@ func (s *exchange) Contacts(users, folders, contacts []string) []ExchangeScope { ) } } + return scopes } @@ -183,12 +191,14 @@ func (s *exchange) ContactFolders(users, folders []string) []ExchangeScope { users = normalize(users) folders = normalize(folders) scopes := []ExchangeScope{} + for _, u := range users { scopes = append( scopes, makeScope[ExchangeScope](u, Group, ExchangeContactFolder, folders), ) } + return scopes } @@ -201,12 +211,14 @@ func (s *exchange) Events(users, events []string) []ExchangeScope { users = normalize(users) events = normalize(events) scopes := []ExchangeScope{} + for _, u := range users { scopes = append( scopes, makeScope[ExchangeScope](u, Item, ExchangeEvent, events), ) } + return scopes } @@ -220,6 +232,7 @@ func (s *exchange) Mails(users, folders, mails []string) []ExchangeScope { folders = normalize(folders) mails = normalize(mails) scopes := []ExchangeScope{} + for _, u := range users { for _, f := range folders { scopes = append( @@ -228,6 +241,7 @@ func (s *exchange) Mails(users, folders, mails []string) []ExchangeScope { ) } } + return scopes } @@ -240,12 +254,14 @@ func (s *exchange) MailFolders(users, folders []string) []ExchangeScope { users = normalize(users) folders = normalize(folders) scopes := []ExchangeScope{} + for _, u := range users { scopes = append( scopes, makeScope[ExchangeScope](u, Group, ExchangeMailFolder, folders), ) } + return scopes } @@ -257,11 +273,13 @@ func (s *exchange) MailFolders(users, folders []string) []ExchangeScope { func (s *exchange) Users(users []string) []ExchangeScope { users = normalize(users) scopes := []ExchangeScope{} + for _, u := range users { scopes = append(scopes, makeScope[ExchangeScope](u, Group, ExchangeContactFolder, Any())) scopes = append(scopes, makeScope[ExchangeScope](u, Item, ExchangeEvent, Any())) scopes = append(scopes, makeScope[ExchangeScope](u, Group, ExchangeMailFolder, Any())) } + return scopes } @@ -327,6 +345,7 @@ func (d ExchangeDestination) GetOrDefault(cat exchangeCategory, current string) if !ok { return current } + return dest } @@ -336,11 +355,14 @@ func (d ExchangeDestination) Set(cat exchangeCategory, dest string) error { if len(dest) == 0 { return nil } + cs := cat.String() if curr, ok := d[cs]; ok { return existingDestinationErr(cs, curr) } + d[cs] = dest + return nil } @@ -424,6 +446,7 @@ func (ec exchangeCategory) leafCat() categorizer { case ExchangeMail, ExchangeMailFolder: return ExchangeMail } + return ec } @@ -451,6 +474,7 @@ func (ec exchangeCategory) pathValues(path []string) map[categorizer]string { if len(path) < 2 { return m } + m[ExchangeUser] = path[1] /* TODO/Notice: @@ -465,20 +489,26 @@ func (ec exchangeCategory) pathValues(path []string) map[categorizer]string { if len(path) < 5 { return m } + m[ExchangeContactFolder] = path[3] m[ExchangeContact] = path[4] + case ExchangeEvent: if len(path) < 4 { return m } + m[ExchangeEvent] = path[3] + case ExchangeMail: if len(path) < 5 { return m } + m[ExchangeMailFolder] = path[3] m[ExchangeMail] = path[4] } + return m } @@ -604,18 +634,23 @@ func (s ExchangeScope) matchesInfo(info *details.ExchangeInfo) bool { if info == nil { return false } + // the scope must define targets to match on filterCat := s.FilterCategory() targets := s.Get(filterCat) + if len(targets) == 0 { return false } + if targets[0] == AnyTgt { return true } + if targets[0] == NoneTgt { return false } + // any of the targets for a given info filter may succeed. for _, target := range targets { switch filterCat { @@ -637,5 +672,6 @@ func (s ExchangeScope) matchesInfo(info *details.ExchangeInfo) bool { } } } + return false } diff --git a/src/pkg/selectors/exchange_test.go b/src/pkg/selectors/exchange_test.go index 35054333e..b627706ec 100644 --- a/src/pkg/selectors/exchange_test.go +++ b/src/pkg/selectors/exchange_test.go @@ -281,13 +281,16 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Exclude_Users() { for _, scope := range scopes { assert.Contains(t, join(u1, u2), scope[ExchangeUser.String()]) + if scope[scopeKeyCategory] == ExchangeContactFolder.String() { assert.Equal(t, scope[ExchangeContact.String()], AnyTgt) assert.Equal(t, scope[ExchangeContactFolder.String()], AnyTgt) } + if scope[scopeKeyCategory] == ExchangeEvent.String() { assert.Equal(t, scope[ExchangeEvent.String()], AnyTgt) } + if scope[scopeKeyCategory] == ExchangeMailFolder.String() { assert.Equal(t, scope[ExchangeMail.String()], AnyTgt) assert.Equal(t, scope[ExchangeMailFolder.String()], AnyTgt) @@ -310,13 +313,16 @@ func (suite *ExchangeSelectorSuite) TestExchangeSelector_Include_Users() { for _, scope := range scopes { assert.Contains(t, join(u1, u2), scope[ExchangeUser.String()]) + if scope[scopeKeyCategory] == ExchangeContactFolder.String() { assert.Equal(t, scope[ExchangeContact.String()], AnyTgt) assert.Equal(t, scope[ExchangeContactFolder.String()], AnyTgt) } + if scope[scopeKeyCategory] == ExchangeEvent.String() { assert.Equal(t, scope[ExchangeEvent.String()], AnyTgt) } + if scope[scopeKeyCategory] == ExchangeMailFolder.String() { assert.Equal(t, scope[ExchangeMail.String()], AnyTgt) assert.Equal(t, scope[ExchangeMailFolder.String()], AnyTgt) @@ -379,6 +385,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeBackup_Scopes() { scopes := eb.Scopes() assert.Len(suite.T(), scopes, 3) + for _, sc := range scopes { cat := sc.Category() suite.T().Run(cat.String(), func(t *testing.T) { @@ -424,6 +431,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeBackup_DiscreteScopes() { expect: Any(), }, } + for _, test := range table { suite.T().Run(test.name, func(t *testing.T) { eb := NewExchangeBackup() @@ -515,7 +523,6 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_Get() { ExchangeMailFolder, ExchangeUser, } - for _, test := range table { suite.T().Run(test.String(), func(t *testing.T) { for _, sc := range scopes { @@ -538,10 +545,12 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_Get() { func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesInfo() { es := NewExchangeRestore() + const ( sender = "smarf@2many.cooks" subject = "I have seen the fnords!" ) + var ( epoch = time.Time{} now = time.Now() @@ -590,6 +599,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeScope_MatchesPath() { fld = "mailFolder" mail = "mailID" ) + var ( path = []string{"tid", usr, "mail", fld, mail} es = NewExchangeRestore() @@ -684,21 +694,26 @@ func (suite *ExchangeSelectorSuite) TestExchangeRestore_Reduce() { Entries: []details.DetailsEntry{}, }, } + for _, r := range refs { deets.Entries = append(deets.Entries, details.DetailsEntry{ RepoRef: r, }) } + return deets } + const ( contact = "tid/uid/contact/cfld/cid" event = "tid/uid/event/eid" mail = "tid/uid/mail/mfld/mid" ) + arr := func(s ...string) []string { return s } + table := []struct { name string deets *details.Details @@ -837,19 +852,24 @@ func (suite *ExchangeSelectorSuite) TestScopesByCategory() { events = es.Events(Any(), Any()) mail = es.MailFolders(Any(), Any()) ) + type expect struct { contact int event int mail int } + type input []scope + makeInput := func(es ...[]ExchangeScope) []scope { mss := []scope{} + for _, sl := range es { for _, s := range sl { mss = append(mss, scope(s)) } } + return mss } cats := map[pathType]exchangeCategory{ @@ -857,6 +877,7 @@ func (suite *ExchangeSelectorSuite) TestScopesByCategory() { exchangeEventPath: ExchangeEvent, exchangeMailPath: ExchangeMail, } + table := []struct { name string scopes input @@ -880,10 +901,12 @@ func (suite *ExchangeSelectorSuite) TestScopesByCategory() { func (suite *ExchangeSelectorSuite) TestPasses() { deets := details.DetailsEntry{} + const ( mid = "mailID" cat = ExchangeMail ) + var ( es = NewExchangeRestore() anyUser = setScopesToDefault(es.Users(Any())) @@ -934,6 +957,7 @@ func (suite *ExchangeSelectorSuite) TestPasses() { func (suite *ExchangeSelectorSuite) TestContains() { target := "fnords" + var ( es = NewExchangeRestore() anyUser = setScopesToDefault(es.Users(Any())) @@ -943,6 +967,7 @@ func (suite *ExchangeSelectorSuite) TestContains() { wrongType = setScopesToDefault(es.Contacts(Any(), Any(), Any())) wrongTypeGoodTarget = setScopesToDefault(es.Contacts(Any(), Any(), Any())) ) + table := []struct { name string scopes []ExchangeScope @@ -977,6 +1002,7 @@ func (suite *ExchangeSelectorSuite) TestIsAny() { specificMail = setScopesToDefault(es.Mails(Any(), Any(), []string{"mail"})) anyMail = setScopesToDefault(es.Mails(Any(), Any(), Any())) ) + table := []struct { name string scopes []ExchangeScope @@ -1041,6 +1067,7 @@ func (suite *ExchangeSelectorSuite) TestExchangeCategory_PathValues() { ExchangeMailFolder: mailPath[3], ExchangeMail: mailPath[4], } + table := []struct { cat exchangeCategory path []string @@ -1064,7 +1091,9 @@ func (suite *ExchangeSelectorSuite) TestExchangeCategory_PathKeys() { event := []categorizer{ExchangeUser, ExchangeEvent} mail := []categorizer{ExchangeUser, ExchangeMailFolder, ExchangeMail} user := []categorizer{ExchangeUser} + var empty []categorizer + table := []struct { cat exchangeCategory expect []categorizer diff --git a/src/pkg/selectors/helpers_test.go b/src/pkg/selectors/helpers_test.go index 07970a74e..e89376d4f 100644 --- a/src/pkg/selectors/helpers_test.go +++ b/src/pkg/selectors/helpers_test.go @@ -24,6 +24,7 @@ func (mc mockCategorizer) String() string { case rootCatStub: return "root" } + return "unknown" } @@ -70,6 +71,7 @@ func (ms mockScope) categorizer() categorizer { case leafCatStub.String(): return leafCatStub } + return unknownCatStub } @@ -94,6 +96,7 @@ func stubScope(match string) mockScope { if len(match) > 0 { sm = match } + return mockScope{ rootCatStub.String(): AnyTgt, scopeKeyCategory: rootCatStub.String(), @@ -125,5 +128,6 @@ func setScopesToDefault[T scopeT](ts []T) []T { for _, s := range ts { s.setDefaults() } + return ts } diff --git a/src/pkg/selectors/onedrive.go b/src/pkg/selectors/onedrive.go index f82981318..25026aaf5 100644 --- a/src/pkg/selectors/onedrive.go +++ b/src/pkg/selectors/onedrive.go @@ -30,6 +30,7 @@ func NewOneDriveBackup() *OneDriveBackup { newSelector(ServiceOneDrive), }, } + return &src } @@ -39,7 +40,9 @@ func (s Selector) ToOneDriveBackup() (*OneDriveBackup, error) { if s.Service != ServiceOneDrive { return nil, badCastErr(ServiceOneDrive, s.Service) } + src := OneDriveBackup{oneDrive{s}} + return &src, nil } @@ -110,9 +113,11 @@ func (s *oneDrive) Filter(scopes ...[]OneDriveScope) { func (s *oneDrive) Users(users []string) []OneDriveScope { users = normalize(users) scopes := []OneDriveScope{} + for _, u := range users { scopes = append(scopes, makeScope[OneDriveScope](u, Group, OneDriveUser, users)) } + return scopes } @@ -197,6 +202,7 @@ func (c oneDriveCategory) pathValues(path []string) map[categorizer]string { if len(path) < 2 { return m } + m[OneDriveUser] = path[1] /* TODO/Notice: @@ -306,12 +312,15 @@ func (s OneDriveScope) matchesInfo(info *details.OneDriveInfo) bool { // the scope must define targets to match on filterCat := s.FilterCategory() targets := s.Get(filterCat) + if len(targets) == 0 { return false } + if targets[0] == AnyTgt { return true } + if targets[0] == NoneTgt { return false } @@ -323,5 +332,6 @@ func (s OneDriveScope) matchesInfo(info *details.OneDriveInfo) bool { return target != NoneTgt } } + return false } diff --git a/src/pkg/selectors/onedrive_test.go b/src/pkg/selectors/onedrive_test.go index 3021a2850..79cd9d072 100644 --- a/src/pkg/selectors/onedrive_test.go +++ b/src/pkg/selectors/onedrive_test.go @@ -60,6 +60,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveBackup_DiscreteScopes() { expect: Any(), }, } + for _, test := range table { suite.T().Run(test.name, func(t *testing.T) { eb := NewOneDriveBackup() @@ -82,6 +83,7 @@ func (suite *OneDriveSelectorSuite) TestOneDriveSelector_Users() { u1 = "u1" u2 = "u2" ) + userScopes := sel.Users([]string{u1, u2}) for _, scope := range userScopes { // Scope value is either u1 or u2 diff --git a/src/pkg/selectors/scopes.go b/src/pkg/selectors/scopes.go index c05ad0835..10429cc8b 100644 --- a/src/pkg/selectors/scopes.go +++ b/src/pkg/selectors/scopes.go @@ -128,6 +128,7 @@ func makeScope[T scopeT]( cat.String(): join(vs...), cat.rootCat().String(): resource, } + return s } @@ -157,19 +158,24 @@ func contains[T scopeT, C categoryT](s T, cat C, target string) bool { if !typeAndCategoryMatches(cat, s.categorizer()) { return false } + if len(target) == 0 { return false } + compare := s[cat.String()] if len(compare) == 0 { return false } + if compare == NoneTgt { return false } + if compare == AnyTgt { return true } + return strings.Contains(compare, target) } @@ -181,6 +187,7 @@ func getCatValue[T scopeT](s T, cat categorizer) []string { if !ok { return None() } + return split(v) } @@ -203,6 +210,7 @@ func isAnyTarget[T scopeT, C categoryT](s T, cat C) bool { if !typeAndCategoryMatches(cat, s.categorizer()) { return false } + return s[cat.String()] == AnyTgt } @@ -229,6 +237,7 @@ func reduce[T scopeT, C categoryT]( for _, ent := range deets.Entries { // todo: use Path pkg for this path := strings.Split(ent.RepoRef, "/") + dc, ok := dataCategories[pathTypeIn(path)] if !ok { continue @@ -249,6 +258,7 @@ func reduce[T scopeT, C categoryT]( reduced := &details.Details{DetailsModel: deets.DetailsModel} reduced.Entries = ents + return reduced } @@ -275,6 +285,7 @@ func pathTypeIn(path []string) pathType { if len(path) < 3 { return unknownPathType } + switch path[2] { case "mail": return exchangeMailPath @@ -283,6 +294,7 @@ func pathTypeIn(path []string) pathType { case "event": return exchangeEventPath } + return unknownPathType } @@ -307,6 +319,7 @@ func scopesByCategory[T scopeT, C categoryT]( } } } + return m } @@ -328,12 +341,14 @@ func passes[T scopeT]( if len(incs) > 0 { // at least one inclusion must apply. var included bool + for _, inc := range incs { if inc.matchesEntry(cat, pathValues, entry) { included = true break } } + if !included { return false } @@ -389,6 +404,7 @@ func matchesPathValues[T scopeT, C categoryT]( } } } + return true } @@ -422,5 +438,6 @@ func typeAndCategoryMatches[C categoryT](a C, b categorizer) bool { if !ok { return false } + return categoryMatches(a, bb) } diff --git a/src/pkg/selectors/scopes_test.go b/src/pkg/selectors/scopes_test.go index 816e28a7f..665be3a99 100644 --- a/src/pkg/selectors/scopes_test.go +++ b/src/pkg/selectors/scopes_test.go @@ -226,6 +226,7 @@ func (suite *SelectorScopesSuite) TestReduce() { dataCats := map[pathType]mockCategorizer{ unknownPathType: rootCatStub, } + for _, test := range reduceTestTable { suite.T().Run(test.name, func(t *testing.T) { ds := deets() @@ -264,6 +265,7 @@ func (suite *SelectorScopesSuite) TestPasses() { cat := rootCatStub pathVals := map[categorizer]string{} entry := details.DetailsEntry{} + for _, test := range reduceTestTable { suite.T().Run(test.name, func(t *testing.T) { sel := test.sel() @@ -284,10 +286,13 @@ func toMockScope(sc []scope) []mockScope { if len(sc) == 0 { return nil } + ms := []mockScope{} + for _, s := range sc { ms = append(ms, mockScope(s)) } + return ms } diff --git a/src/pkg/selectors/selectors.go b/src/pkg/selectors/selectors.go index 7360bab58..8768f7b95 100644 --- a/src/pkg/selectors/selectors.go +++ b/src/pkg/selectors/selectors.go @@ -103,6 +103,7 @@ func (s Selector) String() string { if err != nil { return "error" } + return string(bs) } @@ -113,12 +114,14 @@ func appendScopes[T scopeT](to []scope, scopes ...[]T) []scope { if len(to) == 0 { to = []scope{} } + for _, scopeSl := range scopes { for _, s := range scopeSl { s.setDefaults() to = append(to, scope(s)) } } + return to } @@ -126,9 +129,11 @@ func appendScopes[T scopeT](to []scope, scopes ...[]T) []scope { // future TODO: if Inclues is nil, return filters. func scopes[T scopeT](s Selector) []T { scopes := []T{} + for _, v := range s.Includes { scopes = append(scopes, T(v)) } + return scopes } @@ -158,10 +163,11 @@ func discreteScopes[T scopeT, C categoryT]( for k, v := range t { w[k] = v } + set(w, rootCat, jdid) t = w - } + sl = append(sl, t) } @@ -203,9 +209,11 @@ func (p Printable) Resources() string { if len(s) == 0 { s = resourcesShortFormat(p.Filters) } + if len(s) == 0 { s = "All" } + return s } @@ -213,13 +221,16 @@ func (p Printable) Resources() string { // plus, if more exist, " (len-1 more)" func resourcesShortFormat(m map[string][]string) string { var s string + for k := range m { s = k break } + if len(s) > 0 && len(m) > 1 { s = fmt.Sprintf("%s (%d more)", s, len(m)-1) } + return s } @@ -230,14 +241,18 @@ func toResourceTypeMap(ms []scope) map[string][]string { if len(ms) == 0 { return nil } + r := make(map[string][]string) + for _, m := range ms { res := m[scopeKeyResource] if res == AnyTgt { res = All } + r[res] = addToSet(r[res], m[scopeKeyDataType]) } + return r } @@ -248,11 +263,13 @@ func addToSet(set []string, v string) []string { if len(set) == 0 { return []string{v} } + for _, s := range set { if s == v { return set } } + return append(set, v) } @@ -293,13 +310,16 @@ func normalize(s []string) []string { if len(s) == 0 { return None() } + for _, e := range s { if e == AnyTgt { return Any() } + if e == NoneTgt { return None() } } + return s } diff --git a/src/pkg/selectors/selectors_test.go b/src/pkg/selectors/selectors_test.go index ae8016617..b9a6710ba 100644 --- a/src/pkg/selectors/selectors_test.go +++ b/src/pkg/selectors/selectors_test.go @@ -133,6 +133,7 @@ func (suite *SelectorSuite) TestContains() { does[key.String()] = target doesNot := stubScope("") doesNot[key.String()] = "smarf" + assert.True(t, contains(does, key, target), "does contain") assert.False(t, contains(doesNot, key, target), "does not contain") } diff --git a/src/pkg/storage/common.go b/src/pkg/storage/common.go index d2106de1d..53ea2024e 100644 --- a/src/pkg/storage/common.go +++ b/src/pkg/storage/common.go @@ -26,16 +26,19 @@ func (c CommonConfig) StringConfig() (map[string]string, error) { keyCommonCorsoPassword: c.CorsoPassword, keyCommonKopiaCfgDir: c.KopiaCfgDir, } + return cfg, c.validate() } // CommonConfig retrieves the CommonConfig details from the Storage config. func (s Storage) CommonConfig() (CommonConfig, error) { c := CommonConfig{} + if len(s.Config) > 0 { c.CorsoPassword = orEmptyString(s.Config[keyCommonCorsoPassword]) c.KopiaCfgDir = orEmptyString(s.Config[keyCommonKopiaCfgDir]) } + return c, c.validate() } @@ -44,6 +47,7 @@ func (c CommonConfig) validate() error { if len(c.CorsoPassword) == 0 { return errors.Wrap(errMissingRequired, credentials.CorsoPassword) } + // kopiaCfgFilePath is not required return nil } diff --git a/src/pkg/storage/s3.go b/src/pkg/storage/s3.go index c7818cfda..2c96a0fd7 100644 --- a/src/pkg/storage/s3.go +++ b/src/pkg/storage/s3.go @@ -43,12 +43,14 @@ func (c S3Config) StringConfig() (map[string]string, error) { keyS3SecretKey: c.SecretKey, keyS3SessionToken: c.SessionToken, } + return cfg, c.validate() } // S3Config retrieves the S3Config details from the Storage config. func (s Storage) S3Config() (S3Config, error) { c := S3Config{} + if len(s.Config) > 0 { c.AccessKey = orEmptyString(s.Config[keyS3AccessKey]) c.Bucket = orEmptyString(s.Config[keyS3Bucket]) @@ -57,6 +59,7 @@ func (s Storage) S3Config() (S3Config, error) { c.SecretKey = orEmptyString(s.Config[keyS3SecretKey]) c.SessionToken = orEmptyString(s.Config[keyS3SessionToken]) } + return c, c.validate() } @@ -72,5 +75,6 @@ func (c S3Config) validate() error { return errors.Wrap(errMissingRequired, k) } } + return nil } diff --git a/src/pkg/storage/storage.go b/src/pkg/storage/storage.go index c1730994e..ede8d56a6 100644 --- a/src/pkg/storage/storage.go +++ b/src/pkg/storage/storage.go @@ -38,6 +38,7 @@ type Storage struct { // NewStorage aggregates all the supplied configurations into a single configuration. func NewStorage(p storageProvider, cfgs ...common.StringConfigurer) (Storage, error) { cs, err := common.UnionStringConfigs(cfgs...) + return Storage{ Provider: p, Config: cs, @@ -53,8 +54,10 @@ func orEmptyString(v any) string { fmt.Printf("panic recovery casting %v to string\n", v) } }() + if v == nil { return "" } + return v.(string) } diff --git a/src/pkg/store/backup.go b/src/pkg/store/backup.go index 007c06d98..d02bb1780 100644 --- a/src/pkg/store/backup.go +++ b/src/pkg/store/backup.go @@ -14,10 +14,12 @@ import ( // GetBackup gets a single backup by id. func (w Wrapper) GetBackup(ctx context.Context, backupID model.StableID) (*backup.Backup, error) { b := backup.Backup{} + err := w.Get(ctx, model.BackupSchema, backupID, &b) if err != nil { return nil, errors.Wrap(err, "getting backup") } + return &b, nil } @@ -27,15 +29,20 @@ func (w Wrapper) GetBackups(ctx context.Context) ([]backup.Backup, error) { if err != nil { return nil, err } + bs := make([]backup.Backup, len(bms)) + for i, bm := range bms { b := backup.Backup{} + err := w.GetWithModelStoreID(ctx, model.BackupSchema, bm.ModelStoreID, &b) if err != nil { return nil, err } + bs[i] = b } + return bs, nil } @@ -45,19 +52,23 @@ func (w Wrapper) DeleteBackup(ctx context.Context, backupID model.StableID) erro if err != nil { return err } + if err := w.Delete(ctx, model.BackupDetailsSchema, deets.ID); err != nil { return err } + return w.Delete(ctx, model.BackupSchema, backupID) } // GetDetails gets the backup details by ID. func (w Wrapper) GetDetails(ctx context.Context, detailsID manifest.ID) (*details.Details, error) { d := details.Details{} + err := w.GetWithModelStoreID(ctx, model.BackupDetailsSchema, detailsID, &d) if err != nil { return nil, errors.Wrap(err, "getting details") } + return &d, nil } diff --git a/src/pkg/store/mock/store_mock.go b/src/pkg/store/mock/store_mock.go index 37867bdaf..f9737c129 100644 --- a/src/pkg/store/mock/store_mock.go +++ b/src/pkg/store/mock/store_mock.go @@ -65,6 +65,7 @@ func (mms *MockModelStore) Get( if mms.err != nil { return mms.err } + switch s { case model.BackupSchema: unmarshal(mms.backup, data) @@ -73,6 +74,7 @@ func (mms *MockModelStore) Get( default: return errors.Errorf("schema %s not supported by mock Get", s) } + return nil } @@ -84,16 +86,20 @@ func (mms *MockModelStore) GetIDsForType( if mms.err != nil { return nil, mms.err } + switch s { case model.BackupSchema: b := backup.Backup{} unmarshal(mms.backup, &b) + return []*model.BaseModel{&b.BaseModel}, nil case model.BackupDetailsSchema: d := details.Details{} unmarshal(mms.backup, &d) + return []*model.BaseModel{&d.BaseModel}, nil } + return nil, errors.Errorf("schema %s not supported by mock GetIDsForType", s) } @@ -106,6 +112,7 @@ func (mms *MockModelStore) GetWithModelStoreID( if mms.err != nil { return mms.err } + switch s { case model.BackupSchema: unmarshal(mms.backup, data) @@ -114,6 +121,7 @@ func (mms *MockModelStore) GetWithModelStoreID( default: return errors.Errorf("schema %s not supported by mock GetWithModelStoreID", s) } + return nil } @@ -130,6 +138,7 @@ func (mms *MockModelStore) Put(ctx context.Context, s model.Schema, m model.Mode default: return errors.Errorf("schema %s not supported by mock Put", s) } + return mms.err } @@ -142,5 +151,6 @@ func (mms *MockModelStore) Update(ctx context.Context, s model.Schema, m model.M default: return errors.Errorf("schema %s not supported by mock Update", s) } + return mms.err }