add e2e test sutie (#2645)

Setting up eventual smoke test layers

---

#### Type of change

- [x] 🤖 Test

#### Issue(s)

* #1970

#### Test Plan

- [x]  Unit test
- [x] 💚 E2E
This commit is contained in:
Keepers 2023-02-24 16:41:39 -07:00 committed by GitHub
parent beb3e9ded0
commit fb53cb9709
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 196 additions and 105 deletions

View File

@ -1,103 +0,0 @@
package tester
import (
"os"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"golang.org/x/exp/maps"
)
const (
CorsoLoadTests = "CORSO_LOAD_TESTS"
CorsoCITests = "CORSO_CI_TESTS"
CorsoCLIBackupTests = "CORSO_COMMAND_LINE_BACKUP_TESTS"
CorsoCLIConfigTests = "CORSO_COMMAND_LINE_CONFIG_TESTS"
CorsoCLIRepoTests = "CORSO_COMMAND_LINE_REPO_TESTS"
CorsoCLIRestoreTests = "CORSO_COMMAND_LINE_RESTORE_TESTS"
CorsoCLITests = "CORSO_COMMAND_LINE_TESTS"
CorsoConnectorCreateCollectionTests = "CORSO_CONNECTOR_CREATE_COLLECTION_TESTS"
CorsoConnectorCreateExchangeCollectionTests = "CORSO_CONNECTOR_CREATE_EXCHANGE_COLLECTION_TESTS"
CorsoConnectorCreateSharePointCollectionTests = "CORSO_CONNECTOR_CREATE_SHAREPOINT_COLLECTION_TESTS"
CorsoConnectorDataCollectionTests = "CORSO_CONNECTOR_DATA_COLLECTION_TESTS"
CorsoConnectorExchangeFolderCacheTests = "CORSO_CONNECTOR_EXCHANGE_FOLDER_CACHE_TESTS"
CorsoConnectorRestoreExchangeCollectionTests = "CORSO_CONNECTOR_RESTORE_EXCHANGE_COLLECTION_TESTS"
CorsoGraphConnectorTests = "CORSO_GRAPH_CONNECTOR_TESTS"
CorsoGraphConnectorExchangeTests = "CORSO_GRAPH_CONNECTOR_EXCHANGE_TESTS"
CorsoGraphConnectorOneDriveTests = "CORSO_GRAPH_CONNECTOR_ONE_DRIVE_TESTS"
CorsoGraphConnectorSharePointTests = "CORSO_GRAPH_CONNECTOR_SHAREPOINT_TESTS"
CorsoKopiaWrapperTests = "CORSO_KOPIA_WRAPPER_TESTS"
CorsoModelStoreTests = "CORSO_MODEL_STORE_TESTS"
CorsoOneDriveTests = "CORSO_ONE_DRIVE_TESTS"
CorsoOperationTests = "CORSO_OPERATION_TESTS"
CorsoOperationBackupTests = "CORSO_OPERATION_BACKUP_TESTS"
CorsoRepositoryTests = "CORSO_REPOSITORY_TESTS"
)
// File needs to be a single message .json
// Use: https://developer.microsoft.com/en-us/graph/graph-explorer for details
const CorsoGraphConnectorTestSupportFile = "CORSO_TEST_SUPPORT_FILE"
// RunOnAny takes in a list of env variable names and returns
// an error if all of them are zero valued. Implication being:
// if any of those env vars are truthy, you should run the
// subsequent tests.
func RunOnAny(t *testing.T, tests ...string) {
var l int
for _, test := range tests {
l += len(os.Getenv(test))
}
if l == 0 {
t.Skipf(
"one or more env vars must be flagged to run this test: %v",
strings.Join(tests, ", "))
}
}
// LogTimeOfTest logs the test name and the time that it was run.
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
}
// MustGetEnvVars retrieves the provided env vars from the os.
// Retrieved values are populated into the resulting map.
// If any of the env values are zero length, the test errors.
func MustGetEnvVars(t *testing.T, evs ...string) map[string]string {
vals := map[string]string{}
for _, ev := range evs {
ge := os.Getenv(ev)
require.NotEmpty(t, ev, ev+" env var required for test suite")
vals[ev] = ge
}
return vals
}
// MustGetEnvSls retrieves the provided env vars from the os.
// Retrieved values are populated into the resulting map.
// If any of the env values are zero length, the test errors.
func MustGetEnvSets(t *testing.T, evs ...[]string) map[string]string {
vals := map[string]string{}
for _, ev := range evs {
r := MustGetEnvVars(t, ev...)
maps.Copy(vals, r)
}
return vals
}

View File

@ -1,9 +1,42 @@
package tester
import (
"os"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"golang.org/x/exp/maps"
)
// Flags for declaring which scope of tests to run.
const (
CorsoCITests = "CORSO_CI_TESTS"
CorsoE2ETests = "CORSO_E2E_TESTS"
CorsoLoadTests = "CORSO_LOAD_TESTS"
CorsoCLIBackupTests = "CORSO_COMMAND_LINE_BACKUP_TESTS"
CorsoCLIConfigTests = "CORSO_COMMAND_LINE_CONFIG_TESTS"
CorsoCLIRepoTests = "CORSO_COMMAND_LINE_REPO_TESTS"
CorsoCLIRestoreTests = "CORSO_COMMAND_LINE_RESTORE_TESTS"
CorsoCLITests = "CORSO_COMMAND_LINE_TESTS"
CorsoConnectorCreateCollectionTests = "CORSO_CONNECTOR_CREATE_COLLECTION_TESTS"
CorsoConnectorCreateExchangeCollectionTests = "CORSO_CONNECTOR_CREATE_EXCHANGE_COLLECTION_TESTS"
CorsoConnectorCreateSharePointCollectionTests = "CORSO_CONNECTOR_CREATE_SHAREPOINT_COLLECTION_TESTS"
CorsoConnectorDataCollectionTests = "CORSO_CONNECTOR_DATA_COLLECTION_TESTS"
CorsoConnectorExchangeFolderCacheTests = "CORSO_CONNECTOR_EXCHANGE_FOLDER_CACHE_TESTS"
CorsoConnectorRestoreExchangeCollectionTests = "CORSO_CONNECTOR_RESTORE_EXCHANGE_COLLECTION_TESTS"
CorsoGraphConnectorTests = "CORSO_GRAPH_CONNECTOR_TESTS"
CorsoGraphConnectorExchangeTests = "CORSO_GRAPH_CONNECTOR_EXCHANGE_TESTS"
CorsoGraphConnectorOneDriveTests = "CORSO_GRAPH_CONNECTOR_ONE_DRIVE_TESTS"
CorsoGraphConnectorSharePointTests = "CORSO_GRAPH_CONNECTOR_SHAREPOINT_TESTS"
CorsoKopiaWrapperTests = "CORSO_KOPIA_WRAPPER_TESTS"
CorsoModelStoreTests = "CORSO_MODEL_STORE_TESTS"
CorsoOneDriveTests = "CORSO_ONE_DRIVE_TESTS"
CorsoOperationTests = "CORSO_OPERATION_TESTS"
CorsoOperationBackupTests = "CORSO_OPERATION_BACKUP_TESTS"
CorsoRepositoryTests = "CORSO_REPOSITORY_TESTS"
)
type Suite interface {
@ -11,6 +44,10 @@ type Suite interface {
Run(name string, subtest func()) bool
}
// ---------------------------------------------------------------------------
// Unit
// ---------------------------------------------------------------------------
func NewUnitSuite(t *testing.T) *unitSuite {
return new(unitSuite)
}
@ -19,16 +56,20 @@ type unitSuite struct {
suite.Suite
}
// ---------------------------------------------------------------------------
// Integration
// ---------------------------------------------------------------------------
func NewIntegrationSuite(
t *testing.T,
envSets [][]string,
includeGroups ...string,
runOnAnyEnv ...string,
) *integrationSuite {
RunOnAny(
t,
append(
[]string{CorsoCITests},
includeGroups...,
runOnAnyEnv...,
)...,
)
@ -40,3 +81,80 @@ func NewIntegrationSuite(
type integrationSuite struct {
suite.Suite
}
// ---------------------------------------------------------------------------
// Smoke/e2e
// ---------------------------------------------------------------------------
func NewE2ESuite(
t *testing.T,
envSets [][]string,
runOnAnyEnv ...string,
) *e2eSuite {
RunOnAny(
t,
append(
[]string{CorsoE2ETests},
runOnAnyEnv...,
)...,
)
MustGetEnvSets(t, envSets...)
return new(e2eSuite)
}
type e2eSuite struct {
suite.Suite
}
// ---------------------------------------------------------------------------
// Run Condition Checkers
// ---------------------------------------------------------------------------
// RunOnAny takes in a list of env variable names and returns
// an error if all of them are zero valued. Implication being:
// if any of those env vars are truthy, you should run the
// subsequent tests.
func RunOnAny(t *testing.T, tests ...string) {
var l int
for _, test := range tests {
l += len(os.Getenv(test))
}
if l == 0 {
t.Skipf(
"one or more env vars must be flagged to run this test: %v",
strings.Join(tests, ", "))
}
}
// MustGetEnvVars retrieves the provided env vars from the os.
// Retrieved values are populated into the resulting map.
// If any of the env values are zero length, the test errors.
func MustGetEnvVars(t *testing.T, evs ...string) map[string]string {
vals := map[string]string{}
for _, ev := range evs {
ge := os.Getenv(ev)
require.NotEmpty(t, ev, ev+" env var required for test suite")
vals[ev] = ge
}
return vals
}
// MustGetEnvSls retrieves the provided env vars from the os.
// Retrieved values are populated into the resulting map.
// If any of the env values are zero length, the test errors.
func MustGetEnvSets(t *testing.T, evs ...[]string) map[string]string {
vals := map[string]string{}
for _, ev := range evs {
r := MustGetEnvVars(t, ev...)
maps.Copy(vals, r)
}
return vals
}

View File

@ -0,0 +1,60 @@
package tester_test
import (
"testing"
"github.com/alcionai/corso/src/internal/tester"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)
type TesterUnitSuite struct {
tester.Suite
called bool
}
func TestTesterUnitSuite(t *testing.T) {
suite.Run(t, &TesterUnitSuite{Suite: tester.NewUnitSuite(t)})
}
func (suite *TesterUnitSuite) SetupSuite() {
suite.called = true
}
func (suite *TesterUnitSuite) TestUnitSuite() {
require.True(suite.T(), suite.called)
}
type TesterIntegrationSuite struct {
tester.Suite
called bool
}
func TestTesterIntegrationSuite(t *testing.T) {
suite.Run(t, &TesterIntegrationSuite{Suite: tester.NewIntegrationSuite(t, nil)})
}
func (suite *TesterIntegrationSuite) SetupSuite() {
suite.called = true
}
func (suite *TesterIntegrationSuite) TestIntegrationSuite() {
require.True(suite.T(), suite.called)
}
type TesterE2ESuite struct {
tester.Suite
called bool
}
func TestTesterE2ESuite(t *testing.T) {
suite.Run(t, &TesterE2ESuite{Suite: tester.NewE2ESuite(t, nil)})
}
func (suite *TesterE2ESuite) SetupSuite() {
suite.called = true
}
func (suite *TesterE2ESuite) TestE2ESuite() {
require.True(suite.T(), suite.called)
}

View File

@ -4,6 +4,7 @@ import (
"reflect"
"runtime"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
@ -24,3 +25,18 @@ func AreSameFunc(t *testing.T, expect, have any) {
).Name(),
)
}
// LogTimeOfTest logs the test name and the time that it was run.
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
}