From 505c06441a223f84d6dd81b42a7a56c83ea30f7c Mon Sep 17 00:00:00 2001 From: ashmrtn <3891298+ashmrtn@users.noreply.github.com> Date: Thu, 14 Dec 2023 14:41:00 -0800 Subject: [PATCH] Add config passing test that future PRs will leverage (#4857) We're currently passing some backup options during repo connect which complicates how SDK users can connect to a corso repo. This PR starts to lay the groundwork for passing a discrete set of config parameters to backup operations This PR adds a test around config values passed into the NewBackupOperation function. It checks that the config values stored in the backup operation match what's passed in. It also makes sure the passed in config parameters have all non-zero values so that future changes don't silently pass the test when they shouldn't --- #### Does this PR need a docs update or release note? - [ ] :white_check_mark: Yes, it's included - [ ] :clock1: Yes, but in a later PR - [x] :no_entry: No #### Type of change - [ ] :sunflower: Feature - [ ] :bug: Bugfix - [ ] :world_map: Documentation - [x] :robot: Supportability/Tests - [ ] :computer: CI/Deployment - [ ] :broom: Tech Debt/Cleanup #### Test Plan - [x] :muscle: Manual - [ ] :zap: Unit test - [ ] :green_heart: E2E --- src/internal/operations/backup_test.go | 115 +++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/src/internal/operations/backup_test.go b/src/internal/operations/backup_test.go index 37afe7fab..8190ad95c 100644 --- a/src/internal/operations/backup_test.go +++ b/src/internal/operations/backup_test.go @@ -3,7 +3,9 @@ package operations import ( "context" "encoding/json" + "fmt" stdpath "path" + "reflect" "testing" "time" @@ -12,8 +14,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "golang.org/x/exp/slices" "github.com/alcionai/corso/src/internal/common/prefixmatcher" + "github.com/alcionai/corso/src/internal/common/ptr" strTD "github.com/alcionai/corso/src/internal/common/str/testdata" "github.com/alcionai/corso/src/internal/data" dataMock "github.com/alcionai/corso/src/internal/data/mock" @@ -365,6 +369,117 @@ func TestBackupOpUnitSuite(t *testing.T) { suite.Run(t, &BackupOpUnitSuite{Suite: tester.NewUnitSuite(t)}) } +func checkPopulatedInner(v reflect.Value) error { + if v.IsZero() { + return clues.New("zero-valued field") + } + + if v.Kind() != reflect.Struct { + return nil + } + + var errs *clues.Err + + for i := 0; i < v.NumField(); i++ { + f := v.Field(i) + + if err := checkPopulatedInner(f); err != nil { + errs = clues.Stack(errs, clues.Wrap(err, fmt.Sprintf("field at index %d", i))) + } + } + + return errs.OrNil() +} + +// checkPopulated ensures that input has no zero-valued fields. That helps +// ensure that even as future updates to input happen in other files the changes +// are propagated here due to test failures. +func checkPopulated(t *testing.T, input control.Options) { + err := checkPopulatedInner(reflect.ValueOf(input)) + require.NoError(t, err, clues.ToCore(err)) +} + +// TestNewBackupOperation_configuredOptionsMatchInputOptions ensures that the +// passed in options are properly set in the backup operation during +// intialization. This test is mostly expected to be used while transitioning +// from passing in backup operation config values during repo connect to during +// backup op creation. +func (suite *BackupOpUnitSuite) TestNewBackupOperation_configuredOptionsMatchInputOptions() { + ext := []extensions.CreateItemExtensioner{ + &extensions.MockItemExtensionFactory{}, + } + + opts := control.Options{ + DeltaPageSize: 42, + DisableMetrics: true, + FailureHandling: control.FailAfterRecovery, + ItemExtensionFactory: slices.Clone(ext), + Parallelism: control.Parallelism{ + CollectionBuffer: 4, + ItemFetch: 4, + }, + Repo: repository.Options{ + User: "foo", + Host: "bar", + ViewTimestamp: ptr.To(time.Now()), + ReadOnly: true, + }, + SkipReduce: true, + ToggleFeatures: control.Toggles{ + DisableIncrementals: true, + ForceItemDataDownload: true, + DisableDelta: true, + ExchangeImmutableIDs: true, + RunMigrations: true, + DisableSlidingWindowLimiter: true, + UseDeltaTree: true, + }, + PreviewLimits: control.PreviewItemLimits{ + MaxItems: 42, + MaxItemsPerContainer: 43, + MaxContainers: 44, + MaxBytes: 45, + MaxPages: 46, + Enabled: true, + }, + } + + t := suite.T() + + ctx, flush := tester.NewContext(t) + defer flush() + + // This is a sanity check to make sure all fields on the input control.Options + // are populated. This helps ensure that this chunk of code stays updated as + // options are added to the struct. + checkPopulated(t, opts) + + var ( + kw = &kopia.Wrapper{} + sw = store.NewWrapper(&kopia.ModelStore{}) + ctrl = &mock.Controller{} + acct = account.Account{} + ) + + sel := selectors.Selector{} + sel.DiscreteOwner = "bombadil" + + op, err := NewBackupOperation( + ctx, + opts, + kw, + sw, + ctrl, + acct, + sel, + sel, + evmock.NewBus(), + count.New()) + require.NoError(t, err, clues.ToCore(err)) + + assert.Equal(t, opts, op.Options) +} + func (suite *BackupOpUnitSuite) TestBackupOperation_PersistResults() { var ( kw = &kopia.Wrapper{}