Skip to content

Commit

Permalink
CORE-3855: Enable parallel testing (#24)
Browse files Browse the repository at this point in the history
CORE-3855. This enables using `t.Parallel()` in tests by ensuring every test
is running in its own directory.

See details in https://pkg.go.dev/github.com/gruntwork-io/terratest@v0.40.20/modules/test-structure#CopyTerraformFolderToTemp
  • Loading branch information
morremeyer authored Oct 31, 2023
1 parent ecdc02a commit 7f4db31
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pre-commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- uses: actions/setup-python@c4e89fac7e8767b327bbad6cb4d859eda999cf08 # tag=v4
- uses: actions/setup-go@84cbf8094393cdc5fe1fe1671ff2647332956b1a # tag=v3.2.1
with:
go-version: 1.18.4
go-version: 1.21.3

- name: Setup for pre-commit
run: make setup
Expand Down
51 changes: 30 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ You can use the `DefaultOptions` function for default terraformOptions to be set
- `TerraformDir`, set to the absolute path of the module as the tests are in a subdirectory named `tests`
- `VarFiles` is appended the with the `.tfvars` file in `test/variables` that has the same as the running test

Using `DefaultOptions` ensures that the module directory is copied so that tests can be run in parallel with `t.Parallel()`

### Stages

:information_source: You need stages if you expect e.g. the `terraform plan` to fail for a test and want to validate the errors that occur, see the examples below.
Expand All @@ -64,6 +66,10 @@ Available stages are:

```go
func TestDefaults(t *testing.T) {
// If the test needs to run on its own, e.g. because
// of quota limitations, remove this line
t.Parallel()

helpers.RunNoValidate(t)
}
```
Expand All @@ -76,6 +82,10 @@ When you need to define not only constant variables, but also dynamic ones, you

```go
func TestWithVars(t *testing.T) {
// If the test needs to run on its own, e.g. because
// of quota limitations, remove this line
t.Parallel()

helpers.RunOptionsNoValidate(t, &terraform.Options{
Vars: map[string]interface{}{
"name": uuid.New(),
Expand All @@ -92,18 +102,18 @@ If a test is expected to fail on apply, defer the `destroy` stage and pass an er

```go
func TestS3BucketDefault(t *testing.T) {
defer helpers.StageDestroy(t, TerraformDir)
t.Parallel()
terraformOptions := defaultOptions(t)

// set everything up for the terraform apply later
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: TerraformDir,
Vars: map[string]interface{}{
"name": uuid.New(),
},
})
terraformOptions.Vars = map[string]interface{}{
"name": uuid.New(),
}

helpers.StageSetup(t, TerraformDir, terraformOptions)
helpers.StageApply(t, TerraformDir, func(err error, stdoutStderr string) {
defer helpers.StageDestroy(t, terraformOptions.TerraformDir)

helpers.StageSetup(t, terraformOptions.TerraformDir, terraformOptions)
helpers.StageApply(t, terraformOptions.TerraformDir, func(err error, stdoutStderr string) {
// This error is expected
if err != nil {
if !strings.Contains(stdoutStderr, "Error: Some expected error") {
Expand All @@ -120,21 +130,20 @@ For a test that is expected to fail on plan, use the `Cleanup` function.

```go
func TestS3BucketBackupOnVersioningOff(t *testing.T) {
defer helpers.Cleanup(t, TerraformDir)
t.Parallel()
terraformOptions := defaultOptions(t)

terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: TerraformDir,
// NoColor is important for the string.Contains later
NoColor: true,
Vars: map[string]interface{}{
"name": uuid.New(),
"backup": "on",
"versioning": "Disabled",
},
})
terraformOptions.NoColor = true
terraformOptions.Vars = map[string]interface{}{
"name": uuid.New(),
"backup": "on",
"versioning": "Disabled",
}

defer helpers.Cleanup(t, terraformOptions.TerraformDir)

// The terraform plan is expected to fail as versioning can't be turned off with backups turned on.
helpers.StageSetup(t, TerraformDir, terraformOptions, func(err error, stdoutStderr string) {
helpers.StageSetup(t, terraformOptions.TerraformDir, terraformOptions, func(err error, stdoutStderr string) {
// This error is expected, the precondition failed
if err != nil {
if !strings.Contains(stdoutStderr, "Error: Resource precondition failed") || !strings.Contains(stdoutStderr, "Versioning cannot be disabled when backups are enabled") {
Expand Down
5 changes: 5 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/gruntwork-io/terratest/modules/files"
"github.com/gruntwork-io/terratest/modules/terraform"
test_structure "github.com/gruntwork-io/terratest/modules/test-structure"
"github.com/stretchr/testify/assert"
)

Expand All @@ -28,5 +29,9 @@ func DefaultOptions(t *testing.T, terraformOptions *terraform.Options) *terrafor
terraformOptions.TerraformDir = filepath.Join(path, "../")
}

// This enables parallel testing by ensuring that every TerraformDir lives in its own temporary path
tempTestFolder := test_structure.CopyTerraformFolderToTemp(t, terraformOptions.TerraformDir, ".")
terraformOptions.TerraformDir = tempTestFolder

return terraform.WithDefaultRetryableErrors(t, terraformOptions)
}
2 changes: 1 addition & 1 deletion run.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/gruntwork-io/terratest/modules/terraform"
)

func RunValidate(t *testing.T, terraformOptions terraform.Options, validateFunc func()) {
func RunValidate(t *testing.T, _ terraform.Options, validateFunc func()) {
RunOptionsValidate(t, &terraform.Options{}, validateFunc)
}

Expand Down

0 comments on commit 7f4db31

Please sign in to comment.