Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests/provider: Migrate environment variable functionality into shared package with constants and testing #17197

Merged
merged 1 commit into from
Feb 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions aws/internal/envvar/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package envvar

// Standard AWS environment variables used in the Terraform AWS Provider testing.
// These are not provided as constants in the AWS Go SDK currently.
const (
// Default static credential identifier for tests (AWS Go SDK does not provide this as constant)
// See also AWS_SECRET_ACCESS_KEY and AWS_PROFILE
AwsAccessKeyId = "AWS_ACCESS_KEY_ID"

// Container credentials endpoint
// See also AWS_ACCESS_KEY_ID and AWS_PROFILE
AwsContainerCredentialsFullUri = "AWS_CONTAINER_CREDENTIALS_FULL_URI"

// Default AWS region for tests (AWS Go SDK does not provide this as constant)
AwsDefaultRegion = "AWS_DEFAULT_REGION"

// Default AWS shared configuration profile for tests (AWS Go SDK does not provide this as constant)
AwsProfile = "AWS_PROFILE"

// Default static credential value for tests (AWS Go SDK does not provide this as constant)
// See also AWS_ACCESS_KEY_ID and AWS_PROFILE
AwsSecretAccessKey = "AWS_SECRET_ACCESS_KEY"
)

// Custom environment variables used in the Terraform AWS Provider testing.
// Additions should also be documented in the Environment Variable Dictionary
// of the Maintainers Guide: docs/MAINTAINING.md
const (
// For tests using an alternate AWS account, the equivalent of AWS_ACCESS_KEY_ID for that account
AwsAlternateAccessKeyId = "AWS_ALTERNATE_ACCESS_KEY_ID"

// For tests using an alternate AWS account, the equivalent of AWS_PROFILE for that account
AwsAlternateProfile = "AWS_PROFILE"

// For tests using an alternate AWS region, the equivalent of AWS_DEFAULT_REGION for that account
AwsAlternateRegion = "AWS_ALTERNATE_REGION"

// For tests using an alternate AWS account, the equivalent of AWS_SECRET_ACCESS_KEY for that account
AwsAlternateSecretAccessKey = "AWS_ALTERNATE_SECRET_ACCESS_KEY"

// For tests using a third AWS region, the equivalent of AWS_DEFAULT_REGION for that region
AwsThirdRegion = "AWS_THIRD_REGION"

// For tests requiring GitHub permissions
GithubToken = "GITHUB_TOKEN"

// For tests requiring restricted IAM permissions, an existing IAM Role to assume
// An inline assume role policy is then used to deny actions for the test
TfAccAssumeRoleArn = "TF_ACC_ASSUME_ROLE_ARN"
)
2 changes: 2 additions & 0 deletions aws/internal/envvar/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// envvar contains constants and helpers for environment variable usage in testing.
package envvar
16 changes: 16 additions & 0 deletions aws/internal/envvar/funcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package envvar

import (
"os"
)

// GetWithDefault gets an environment variable value if non-empty or returns the default.
func GetWithDefault(variable string, defaultValue string) string {
value := os.Getenv(variable)

if value == "" {
return defaultValue
}

return value
}
50 changes: 50 additions & 0 deletions aws/internal/envvar/funcs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package envvar_test

import (
"os"
"testing"

"github.com/terraform-providers/terraform-provider-aws/aws/internal/envvar"
)

func TestGetWithDefault(t *testing.T) {
envVar := "TESTENVVAR_GETWITHDEFAULT"

t.Run("missing", func(t *testing.T) {
want := "default"

os.Unsetenv(envVar)

got := envvar.GetWithDefault(envVar, want)

if got != want {
t.Fatalf("expected %s, got %s", want, got)
}
})

t.Run("empty", func(t *testing.T) {
want := "default"

os.Setenv(envVar, "")
defer os.Unsetenv(envVar)

got := envvar.GetWithDefault(envVar, want)

if got != want {
t.Fatalf("expected %s, got %s", want, got)
}
})

t.Run("not empty", func(t *testing.T) {
want := "notempty"

os.Setenv(envVar, want)
defer os.Unsetenv(envVar)

got := envvar.GetWithDefault(envVar, "default")

if got != want {
t.Fatalf("expected %s, got %s", want, got)
}
})
}
56 changes: 56 additions & 0 deletions aws/internal/envvar/testing_funcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package envvar

import (
"os"

"github.com/mitchellh/go-testing-interface"
)

// TestFailIfAllEmpty verifies that at least one environment variable is non-empty or fails the test.
//
// If at lease one environment variable is non-empty, returns the first name and value.
func TestFailIfAllEmpty(t testing.T, names []string, usageMessage string) (string, string) {
t.Helper()

for _, variable := range names {
value := os.Getenv(variable)

if value != "" {
return variable, value
}
}

t.Fatalf("at least one environment variable of %v must be set. Usage: %s", names, usageMessage)

return "", ""
}

// TestFailIfEmpty verifies that an environment variable is non-empty or fails the test.
//
// For acceptance tests, this function must be used outside PreCheck functions to set values for configurations.
func TestFailIfEmpty(t testing.T, name string, usageMessage string) string {
t.Helper()

value := os.Getenv(name)

if value == "" {
t.Fatalf("environment variable %s must be set. Usage: %s", name, usageMessage)
}

return value
}

// TestSkipIfEmpty verifies that an environment variable is non-empty or skips the test.
//
// For acceptance tests, this function must be used outside PreCheck functions to set values for configurations.
func TestSkipIfEmpty(t testing.T, name string, usageMessage string) string {
t.Helper()

value := os.Getenv(name)

if value == "" {
t.Skipf("skipping test; environment variable %s must be set. Usage: %s", name, usageMessage)
}

return value
}
170 changes: 170 additions & 0 deletions aws/internal/envvar/testing_funcs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package envvar_test

import (
"os"
"testing"

testingiface "github.com/mitchellh/go-testing-interface"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/envvar"
)

func TestTestFailIfAllEmpty(t *testing.T) {
envVar1 := "TESTENVVAR_FAILIFALLEMPTY1"
envVar2 := "TESTENVVAR_FAILIFALLEMPTY2"
envVars := []string{envVar1, envVar2}

t.Run("missing", func(t *testing.T) {
defer testingifaceRecover()

for _, envVar := range envVars {
os.Unsetenv(envVar)
}

envvar.TestFailIfAllEmpty(&testingiface.RuntimeT{}, envVars, "usage")

t.Fatal("expected to fail previously")
})

t.Run("all empty", func(t *testing.T) {
defer testingifaceRecover()

os.Setenv(envVar1, "")
os.Setenv(envVar2, "")
defer unsetEnvVars(envVars)

envvar.TestFailIfAllEmpty(&testingiface.RuntimeT{}, envVars, "usage")

t.Fatal("expected to fail previously")
})

t.Run("some empty", func(t *testing.T) {
wantValue := "pickme"

os.Setenv(envVar1, "")
os.Setenv(envVar2, wantValue)
defer unsetEnvVars(envVars)

gotName, gotValue := envvar.TestFailIfAllEmpty(&testingiface.RuntimeT{}, envVars, "usage")

if gotName != envVar2 {
t.Fatalf("expected name: %s, got: %s", envVar2, gotName)
}

if gotValue != wantValue {
t.Fatalf("expected value: %s, got: %s", wantValue, gotValue)
}
})

t.Run("all not empty", func(t *testing.T) {
wantValue := "pickme"

os.Setenv(envVar1, wantValue)
os.Setenv(envVar2, "other")
defer unsetEnvVars(envVars)

gotName, gotValue := envvar.TestFailIfAllEmpty(&testingiface.RuntimeT{}, envVars, "usage")

if gotName != envVar1 {
t.Fatalf("expected name: %s, got: %s", envVar1, gotName)
}

if gotValue != wantValue {
t.Fatalf("expected value: %s, got: %s", wantValue, gotValue)
}
})
}

func TestTestFailIfEmpty(t *testing.T) {
envVar := "TESTENVVAR_FAILIFEMPTY"

t.Run("missing", func(t *testing.T) {
defer testingifaceRecover()

os.Unsetenv(envVar)

envvar.TestFailIfEmpty(&testingiface.RuntimeT{}, envVar, "usage")

t.Fatal("expected to fail previously")
})

t.Run("empty", func(t *testing.T) {
defer testingifaceRecover()

os.Setenv(envVar, "")
defer os.Unsetenv(envVar)

envvar.TestFailIfEmpty(&testingiface.RuntimeT{}, envVar, "usage")

t.Fatal("expected to fail previously")
})

t.Run("not empty", func(t *testing.T) {
want := "notempty"

os.Setenv(envVar, want)
defer os.Unsetenv(envVar)

got := envvar.TestFailIfEmpty(&testingiface.RuntimeT{}, envVar, "usage")

if got != want {
t.Fatalf("expected value: %s, got: %s", want, got)
}
})
}

func TestTestSkipIfEmpty(t *testing.T) {
envVar := "TESTENVVAR_SKIPIFEMPTY"

t.Run("missing", func(t *testing.T) {
mockT := &testingiface.RuntimeT{}

os.Unsetenv(envVar)

envvar.TestSkipIfEmpty(mockT, envVar, "usage")

if !mockT.Skipped() {
t.Fatal("expected to skip previously")
}
})

t.Run("empty", func(t *testing.T) {
mockT := &testingiface.RuntimeT{}

os.Setenv(envVar, "")
defer os.Unsetenv(envVar)

envvar.TestSkipIfEmpty(mockT, envVar, "usage")

if !mockT.Skipped() {
t.Fatal("expected to skip previously")
}
})

t.Run("not empty", func(t *testing.T) {
want := "notempty"

os.Setenv(envVar, want)
defer os.Unsetenv(envVar)

got := envvar.TestSkipIfEmpty(&testingiface.RuntimeT{}, envVar, "usage")

if got != want {
t.Fatalf("expected value: %s, got: %s", want, got)
}
})
}

func testingifaceRecover() {
r := recover()

// this string is hardcoded in github.com/mitchellh/go-testing-interface
if s, ok := r.(string); !ok || s != "testing.T failed, see logs for output (if any)" {
panic(r)
}
}

func unsetEnvVars(envVars []string) {
for _, envVar := range envVars {
os.Unsetenv(envVar)
}
}
Loading