<!-- PR description--> --- #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [x] ⛔ No #### Type of change <!--- Please check the type of change your PR introduces: ---> - [ ] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Supportability/Tests - [x] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup #### Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> * #<issue> #### Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [ ] ⚡ Unit test - [ ] 💚 E2E
277 lines
8.5 KiB
Go
277 lines
8.5 KiB
Go
package tconfig
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/alcionai/clues"
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/exp/maps"
|
|
|
|
"github.com/alcionai/corso/src/pkg/account"
|
|
)
|
|
|
|
const (
|
|
// S3 config
|
|
TestCfgBucket = "bucket"
|
|
TestCfgEndpoint = "endpoint"
|
|
TestCfgPrefix = "prefix"
|
|
TestCfgStorageProvider = "provider"
|
|
TestCfgFilesystemPath = "path"
|
|
|
|
// M365 config
|
|
TestCfgAzureTenantID = "azure_tenantid"
|
|
TestCfgSecondarySiteID = "secondarym365siteid"
|
|
TestCfgSiteID = "m365siteid"
|
|
TestCfgSiteURL = "m365siteurl"
|
|
TestCfgTeamID = "m365teamid"
|
|
TestCfgTeamSiteID = "m365teamsiteid"
|
|
TestCfgGroupID = "m365groupid"
|
|
TestCfgUserID = "m365userid"
|
|
TestCfgSecondaryUserID = "secondarym365userid"
|
|
TestCfgSecondaryGroupID = "secondarym365groupid"
|
|
TestCfgSecondaryTeamID = "secondarym365teamid"
|
|
TestCfgTertiaryUserID = "tertiarym365userid"
|
|
TestCfgLoadTestUserID = "loadtestm365userid"
|
|
TestCfgLoadTestOrgUsers = "loadtestm365orgusers"
|
|
TestCfgAccountProvider = "account_provider"
|
|
TestCfgUnlicensedUserID = "unlicensedm365userid"
|
|
)
|
|
|
|
// test specific env vars
|
|
const (
|
|
EnvCorsoM365LoadTestUserID = "CORSO_M365_LOAD_TEST_USER_ID"
|
|
EnvCorsoM365LoadTestOrgUsers = "CORSO_M365_LOAD_TEST_ORG_USERS"
|
|
EnvCorsoM365TestSiteID = "CORSO_M365_TEST_SITE_ID"
|
|
EnvCorsoM365TestSiteURL = "CORSO_M365_TEST_SITE_URL"
|
|
EnvCorsoM365TestTeamID = "CORSO_M365_TEST_TEAM_ID"
|
|
EnvCorsoM365TestTeamSiteID = "CORSO_M365_TEST_TEAM_SITE_ID"
|
|
EnvCorsoSecondaryM365TestTeamID = "CORSO_SECONDARY_M365_TEST_TEAM_ID"
|
|
EnvCorsoM365TestGroupID = "CORSO_M365_TEST_GROUP_ID"
|
|
EnvCorsoSecondaryM365TestGroupID = "CORSO_SECONDARY_M365_TEST_GROUP_ID"
|
|
EnvCorsoM365TestUserID = "CORSO_M365_TEST_USER_ID"
|
|
EnvCorsoSecondaryM365TestSiteID = "CORSO_SECONDARY_M365_TEST_SITE_ID"
|
|
EnvCorsoSecondaryM365TestUserID = "CORSO_SECONDARY_M365_TEST_USER_ID"
|
|
EnvCorsoTertiaryM365TestUserID = "CORSO_TERTIARY_M365_TEST_USER_ID"
|
|
EnvCorsoTestConfigFilePath = "CORSO_TEST_CONFIG_FILE"
|
|
EnvCorsoUnlicensedM365TestUserID = "CORSO_M365_TEST_UNLICENSED_USER"
|
|
)
|
|
|
|
// global to hold the test config results.
|
|
var testConfig map[string]string
|
|
|
|
// call this instead of returning testConfig directly.
|
|
func cloneTestConfig() map[string]string {
|
|
if testConfig == nil {
|
|
return map[string]string{}
|
|
}
|
|
|
|
return maps.Clone(testConfig)
|
|
}
|
|
|
|
func NewTestViper() (*viper.Viper, error) {
|
|
vpr := viper.New()
|
|
|
|
configFilePath := os.Getenv(EnvCorsoTestConfigFilePath)
|
|
if len(configFilePath) == 0 {
|
|
return vpr, nil
|
|
}
|
|
|
|
// Or use a custom file location
|
|
ext := filepath.Ext(configFilePath)
|
|
if len(ext) == 0 {
|
|
return nil, clues.New("corso_test requires an extension")
|
|
}
|
|
|
|
vpr.SetConfigFile(configFilePath)
|
|
vpr.AddConfigPath(filepath.Dir(configFilePath))
|
|
vpr.SetConfigType(ext[1:])
|
|
|
|
fileName := filepath.Base(configFilePath)
|
|
fileName = strings.TrimSuffix(fileName, ext)
|
|
vpr.SetConfigName(fileName)
|
|
|
|
return vpr, nil
|
|
}
|
|
|
|
// reads a corso configuration file with values specific to
|
|
// local integration test controls. Populates values with
|
|
// defaults where standard.
|
|
func ReadTestConfig() (map[string]string, error) {
|
|
if testConfig != nil {
|
|
return cloneTestConfig(), nil
|
|
}
|
|
|
|
vpr, err := NewTestViper()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// only error if reading an existing file failed. No problem if we're missing files.
|
|
if err = vpr.ReadInConfig(); err != nil {
|
|
_, ok := err.(viper.ConfigFileNotFoundError)
|
|
if !ok {
|
|
return nil, clues.Wrap(err, "reading config file: "+viper.ConfigFileUsed())
|
|
}
|
|
}
|
|
|
|
testEnv := map[string]string{}
|
|
fallbackTo(testEnv, TestCfgStorageProvider, vpr.GetString(TestCfgStorageProvider))
|
|
fallbackTo(testEnv, TestCfgAccountProvider, vpr.GetString(TestCfgAccountProvider))
|
|
fallbackTo(testEnv, TestCfgBucket, os.Getenv("S3_BUCKET"), vpr.GetString(TestCfgBucket))
|
|
fallbackTo(testEnv, TestCfgEndpoint, vpr.GetString(TestCfgEndpoint), "s3.amazonaws.com")
|
|
fallbackTo(testEnv, TestCfgPrefix, vpr.GetString(TestCfgPrefix))
|
|
fallbackTo(testEnv, TestCfgAzureTenantID, os.Getenv(account.AzureTenantID), vpr.GetString(TestCfgAzureTenantID))
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgUserID,
|
|
os.Getenv(EnvCorsoM365TestUserID),
|
|
vpr.GetString(TestCfgUserID),
|
|
"LynneR@10rqc2.onmicrosoft.com")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgSecondaryUserID,
|
|
os.Getenv(EnvCorsoSecondaryM365TestUserID),
|
|
vpr.GetString(TestCfgSecondaryUserID),
|
|
"AdeleV@10rqc2.onmicrosoft.com")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgTertiaryUserID,
|
|
os.Getenv(EnvCorsoTertiaryM365TestUserID),
|
|
vpr.GetString(TestCfgTertiaryUserID),
|
|
"PradeepG@10rqc2.onmicrosoft.com")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgLoadTestUserID,
|
|
os.Getenv(EnvCorsoM365LoadTestUserID),
|
|
vpr.GetString(TestCfgLoadTestUserID),
|
|
"leeg@10rqc2.onmicrosoft.com")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgLoadTestOrgUsers,
|
|
os.Getenv(EnvCorsoM365LoadTestOrgUsers),
|
|
vpr.GetString(TestCfgLoadTestOrgUsers),
|
|
"AdeleV@10rqc2.onmicrosoft.com,LynneR@10rqc2.onmicrosoft.com")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgSiteID,
|
|
os.Getenv(EnvCorsoM365TestSiteID),
|
|
vpr.GetString(TestCfgSiteID),
|
|
"4892edf5-2ebf-46be-a6e5-a40b2cbf1c1a,38ab6d06-fc82-4417-af93-22d8733c22be")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgTeamID,
|
|
os.Getenv(EnvCorsoM365TestTeamID),
|
|
vpr.GetString(TestCfgTeamID),
|
|
"6f24b40d-b13d-4752-980f-f5fb9fba7aa0")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgTeamSiteID,
|
|
os.Getenv(EnvCorsoM365TestTeamSiteID),
|
|
vpr.GetString(TestCfgTeamSiteID),
|
|
"8df7082a-62eb-4165-97f9-ead8cf04c0d8,11810f05-e8bd-45e2-9728-92e434260750")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgSecondaryTeamID,
|
|
os.Getenv(EnvCorsoSecondaryM365TestTeamID),
|
|
vpr.GetString(TestCfgSecondaryTeamID),
|
|
"20cda3c0-6f9a-4286-9f2f-bb284e1f79c9")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgGroupID,
|
|
os.Getenv(EnvCorsoM365TestGroupID),
|
|
vpr.GetString(TestCfgGroupID),
|
|
"6f24b40d-b13d-4752-980f-f5fb9fba7aa0")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgSecondaryGroupID,
|
|
os.Getenv(EnvCorsoSecondaryM365TestGroupID),
|
|
vpr.GetString(TestCfgSecondaryGroupID),
|
|
"20cda3c0-6f9a-4286-9f2f-bb284e1f79c9")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgSiteURL,
|
|
os.Getenv(EnvCorsoM365TestSiteURL),
|
|
vpr.GetString(TestCfgSiteURL),
|
|
"https://10rqc2.sharepoint.com/sites/CorsoCI")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgSecondarySiteID,
|
|
os.Getenv(EnvCorsoSecondaryM365TestSiteID),
|
|
vpr.GetString(TestCfgSecondarySiteID),
|
|
"053684d8-ca6c-4376-a03e-2567816bb091,9b3e9abe-6a5e-4084-8b44-ea5a356fe02c")
|
|
fallbackTo(
|
|
testEnv,
|
|
TestCfgUnlicensedUserID,
|
|
os.Getenv(EnvCorsoUnlicensedM365TestUserID),
|
|
vpr.GetString(TestCfgUnlicensedUserID),
|
|
"testevents@10rqc2.onmicrosoft.com")
|
|
|
|
testEnv[EnvCorsoTestConfigFilePath] = os.Getenv(EnvCorsoTestConfigFilePath)
|
|
testConfig = testEnv
|
|
|
|
return cloneTestConfig(), nil
|
|
}
|
|
|
|
// MakeTempTestConfigClone makes a copy of the test config file in a temp directory.
|
|
// This allows tests which interface with reading and writing to a config file
|
|
// (such as the CLI) to safely manipulate file contents without amending the user's
|
|
// original file.
|
|
//
|
|
// Attempts to copy values sourced from the caller's test config file.
|
|
// The overrides prop replaces config values with the provided value.
|
|
//
|
|
// Returns a filepath string pointing to the location of the temp file.
|
|
func MakeTempTestConfigClone(t *testing.T, overrides map[string]string) (*viper.Viper, string) {
|
|
cfg, err := ReadTestConfig()
|
|
require.NoError(t, err, "reading tester config", clues.ToCore(err))
|
|
|
|
fName := filepath.Base(os.Getenv(EnvCorsoTestConfigFilePath))
|
|
if len(fName) == 0 || fName == "." || fName == "/" {
|
|
fName = ".corso_test.toml"
|
|
}
|
|
|
|
tDir := t.TempDir()
|
|
tDirFp := filepath.Join(tDir, fName)
|
|
|
|
_, err = os.Create(tDirFp)
|
|
require.NoError(t, err, "creating temp test dir", clues.ToCore(err))
|
|
|
|
ext := filepath.Ext(fName)
|
|
vpr := viper.New()
|
|
vpr.SetConfigFile(tDirFp)
|
|
vpr.AddConfigPath(tDir)
|
|
vpr.SetConfigType(strings.TrimPrefix(ext, "."))
|
|
vpr.SetConfigName(strings.TrimSuffix(fName, ext))
|
|
vpr.Set("corso-testing", true)
|
|
|
|
for k, v := range cfg {
|
|
vpr.Set(k, v)
|
|
}
|
|
|
|
for k, v := range overrides {
|
|
vpr.Set(k, v)
|
|
}
|
|
|
|
err = vpr.WriteConfig()
|
|
require.NoError(t, err, "writing temp dir viper config file", clues.ToCore(err))
|
|
|
|
return vpr, tDirFp
|
|
}
|
|
|
|
// writes the first non-zero valued string to the map at the key.
|
|
// fallback priority should match viper ordering (manually handled
|
|
// here since viper fails to provide fallbacks on fileNotFoundErr):
|
|
// manual overrides > flags > env vars > config file > default value
|
|
func fallbackTo(m map[string]string, key string, fallbacks ...string) {
|
|
for _, fb := range fallbacks {
|
|
if len(fb) > 0 {
|
|
m[key] = fb
|
|
return
|
|
}
|
|
}
|
|
}
|