From e061ce7c7319af3cc41ef2124b158ffeab19f928 Mon Sep 17 00:00:00 2001 From: Keepers Date: Mon, 26 Sep 2022 18:21:30 -0600 Subject: [PATCH] implement load tests (#937) ## Description Adds the load test func calls and asserts for both exchange and onedrive. ## Type of change - [x] :robot: Test ## Issue(s) * #902 ## Test Plan - [x] :green_heart: E2E --- .github/workflows/load_test.yml | 91 ++++++------ src/pkg/repository/repository_load_test.go | 160 +++++++++++++++++++-- 2 files changed, 191 insertions(+), 60 deletions(-) diff --git a/.github/workflows/load_test.yml b/.github/workflows/load_test.yml index 8d0ab1544..f68eda14e 100644 --- a/.github/workflows/load_test.yml +++ b/.github/workflows/load_test.yml @@ -9,53 +9,54 @@ permissions: id-token: write contents: read -Load-Tests: - environment: Testing - runs-on: ubuntu-latest - defaults: - run: - working-directory: src - steps: - - uses: actions/checkout@v3 +jobs: + Load-Tests: + environment: Testing + runs-on: ubuntu-latest + defaults: + run: + working-directory: src + steps: + - uses: actions/checkout@v3 - - name: Setup Golang with cache - uses: magnetikonline/action-golang-cache@v3 - with: - go-version-file: src/go.mod + - name: Setup Golang with cache + uses: magnetikonline/action-golang-cache@v3 + with: + go-version-file: src/go.mod - # Install gotestfmt - - name: Set up gotestfmt - run: go install github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest + # Install gotestfmt + - name: Set up gotestfmt + run: go install github.com/haveyoudebuggedit/gotestfmt/v2/cmd/gotestfmt@latest - # AWS creds - - name: Configure AWS credentials from Test account - uses: aws-actions/configure-aws-credentials@v1 - with: - role-to-assume: arn:aws:iam::951767375776:role/corso-testing-role - role-session-name: integration-testing - aws-region: us-east-1 + # AWS creds + - name: Configure AWS credentials from Test account + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: arn:aws:iam::951767375776:role/corso-testing-role + role-session-name: integration-testing + aws-region: us-east-1 - # run the tests - - name: Integration Tests - env: - CORSO_LOAD_TESTS: true - CLIENT_ID: ${{ secrets.CLIENT_ID }} - CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} - CORSO_PASSPHRASE: ${{ secrets.INTEGRATION_TEST_CORSO_PASSPHRASE }} - TENANT_ID: ${{ secrets.TENANT_ID }} - run: | - set -euo pipefail - go test \ - -json \ - -v \ - -count=1 \ - --timeout 12h \ - ./... 2>&1 | tee /tmp/gotest.log | gotestfmt -hide successful-tests + # run the tests + - name: Integration Tests + env: + CORSO_LOAD_TESTS: true + CLIENT_ID: ${{ secrets.CLIENT_ID }} + CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} + CORSO_PASSPHRASE: ${{ secrets.INTEGRATION_TEST_CORSO_PASSPHRASE }} + TENANT_ID: ${{ secrets.TENANT_ID }} + run: | + set -euo pipefail + go test \ + -json \ + -v \ + -count=1 \ + --timeout 12h \ + ./... 2>&1 | tee /tmp/gotest.log | gotestfmt -hide successful-tests - # Upload the original go test log as an artifact for later review. - - name: Upload test log - uses: actions/upload-artifact@v2 - with: - name: test-log - path: /tmp/gotest.log - if-no-files-found: error \ No newline at end of file + # Upload the original go test log as an artifact for later review. + - name: Upload test log + uses: actions/upload-artifact@v2 + with: + name: test-log + path: /tmp/gotest.log + if-no-files-found: error \ No newline at end of file diff --git a/src/pkg/repository/repository_load_test.go b/src/pkg/repository/repository_load_test.go index 0e3864921..a9eafa575 100644 --- a/src/pkg/repository/repository_load_test.go +++ b/src/pkg/repository/repository_load_test.go @@ -4,14 +4,17 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "github.com/alcionai/corso/src/internal/operations" "github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/pkg/account" "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/logger" "github.com/alcionai/corso/src/pkg/repository" + "github.com/alcionai/corso/src/pkg/selectors" "github.com/alcionai/corso/src/pkg/storage" ) @@ -38,6 +41,98 @@ func initM365Repo(t *testing.T) ( return ctx, repo, ac, st } +//revive:disable:context-as-argument +func runBackupLoadTest( + t *testing.T, + ctx context.Context, + b *operations.BackupOperation, + name string, +) { + //revive:enable:context-as-argument + t.Run("backup_"+name, func(t *testing.T) { + require.NoError(t, b.Run(ctx), "running backup") + require.NotEmpty(t, b.Results, "has results after run") + assert.NotEmpty(t, b.Results.BackupID, "has an ID after run") + assert.Equal(t, b.Status, operations.Completed, "backup status") + assert.Less(t, 0, b.Results.ItemsRead, "items read") + assert.Less(t, 0, b.Results.ItemsWritten, "items written") + assert.Less(t, int64(0), b.Results.BytesUploaded, "bytes uploaded") + assert.Less(t, 0, b.Results.ResourceOwners, "resource owners") + assert.Zero(t, b.Results.ReadErrors, "read errors") + assert.Zero(t, b.Results.WriteErrors, "write errors") + }) +} + +//revive:disable:context-as-argument +func runBackupListLoadTest( + t *testing.T, + ctx context.Context, + r repository.Repository, + name, expectID string, +) { + //revive:enable:context-as-argument + t.Run("backup_list_"+name, func(t *testing.T) { + bs, err := r.Backups(ctx) + require.NoError(t, err, "retrieving backups") + require.Less(t, 0, len(bs), "at least one backup is recorded") + + var found bool + + for _, b := range bs { + bid := b.ID + assert.NotEmpty(t, bid, "iterating backup ids") + + if string(bid) == expectID { + found = true + } + } + + assert.True(t, found, "expected backup id "+expectID+" found in backups") + }) +} + +//revive:disable:context-as-argument +func runBackupDetailsLoadTest( + t *testing.T, + ctx context.Context, + r repository.Repository, + name, backupID string, +) { + //revive:enable:context-as-argument + require.NotEmpty(t, backupID, "backup ID to retrieve deails") + + t.Run("backup_details_"+name, func(t *testing.T) { + ds, b, err := r.BackupDetails(ctx, backupID) + require.NoError(t, err, "retrieving details in backup "+backupID) + require.NotNil(t, ds, "backup details") + require.NotNil(t, b, "backup") + assert.Equal(t, b.ItemsWritten, len(ds.Entries)) + }) +} + +//revive:disable:context-as-argument +func runRestoreLoadTest( + t *testing.T, + ctx context.Context, + r operations.RestoreOperation, + name string, + expectItemCount int, +) { + //revive:enable:context-as-argument + t.Run("restore_"+name, func(t *testing.T) { + t.Skip("skipping restore handling while investigating performance") + require.NoError(t, r.Run(ctx), "running restore") + require.NotEmpty(t, r.Results, "has results after run") + assert.Equal(t, r.Status, operations.Completed, "restore status") + assert.Less(t, 0, r.Results.ItemsRead, "items read") + assert.Less(t, 0, r.Results.ItemsWritten, "items written") + assert.Less(t, 0, r.Results.ResourceOwners, "resource owners") + assert.Zero(t, r.Results.ReadErrors, "read errors") + assert.Zero(t, r.Results.WriteErrors, "write errors") + assert.Equal(t, expectItemCount, r.Results.ItemsWritten, "backup and restore wrote the same count of items") + }) +} + // ------------------------------------------------------------------------------------------------ // Exchange // ------------------------------------------------------------------------------------------------ @@ -76,20 +171,39 @@ func (suite *RepositoryLoadTestExchangeSuite) TeardownTest() { } func (suite *RepositoryLoadTestExchangeSuite) TestExchange() { - // var ( - // t = suite.T() - // ctx = context.Background() - // ) + var ( + t = suite.T() + ctx = context.Background() + r = suite.repo + service = "exchange" + ) - // t.parallel() + t.Parallel() + + m356User := tester.M365UserID(t) // backup + bsel := selectors.NewExchangeBackup() + bsel.Include(bsel.Users([]string{m356User})) + // bsel.Include(bsel.Users(selectors.Any())) - // list + b, err := r.NewBackup(ctx, bsel.Selector) + require.NoError(t, err) - // details + runBackupLoadTest(t, ctx, &b, service) + bid := string(b.Results.BackupID) + + runBackupListLoadTest(t, ctx, r, service, bid) + runBackupDetailsLoadTest(t, ctx, r, service, bid) // restore + rsel, err := bsel.ToExchangeRestore() + require.NoError(t, err) + + rst, err := r.NewRestore(ctx, bid, rsel.Selector) + require.NoError(t, err) + + runRestoreLoadTest(t, ctx, rst, service, b.Results.ItemsWritten) } // ------------------------------------------------------------------------------------------------ @@ -129,19 +243,35 @@ func (suite *RepositoryLoadTestOneDriveSuite) TeardownTest() { logger.Flush(suite.ctx) } -func (suite *RepositoryLoadTestOneDriveSuite) TestExchange() { - // var ( - // t = suite.T() - // ctx = context.Background() - // ) +func (suite *RepositoryLoadTestOneDriveSuite) TestOneDrive() { + var ( + t = suite.T() + ctx = context.Background() + r = suite.repo + service = "one_drive" + ) - // t.parallel() + t.Parallel() // backup + bsel := selectors.NewOneDriveBackup() + bsel.Include(bsel.Users(selectors.Any())) - // list + b, err := r.NewBackup(ctx, bsel.Selector) + require.NoError(t, err) - // details + runBackupLoadTest(t, ctx, &b, service) + bid := string(b.Results.BackupID) + + runBackupListLoadTest(t, ctx, r, service, bid) + runBackupDetailsLoadTest(t, ctx, r, service, bid) // restore + rsel, err := bsel.ToOneDriveRestore() + require.NoError(t, err) + + rst, err := r.NewRestore(ctx, bid, rsel.Selector) + require.NoError(t, err) + + runRestoreLoadTest(t, ctx, rst, service, b.Results.ItemsWritten) }