Terratest multiple targets

I am using terrates to test my terraform code. My code have 2 modules so I managed to configure terratest to use target option while configuring the terraformOptions and it creates both modules.

However, when it comes to clean everything, it cleans only the last module using Defer. Here is my code.

    package test

import (
	"fmt"
	"os"
	"testing"

	"github.com/gruntwork-io/terratest/modules/terraform"

	test_structure "github.com/gruntwork-io/terratest/modules/test-structure"
)

func configureTerraformOptions(t *testing.T, terraformDir string, tfModule string) (*terraform.Options) {

	awsRegion := os.Getenv("AWS_REGION")

	terraformOptions := &terraform.Options{

		TerraformDir: terraformDir,
		Targets: []string{tfModule},
		Vars: map[string]interface{}{
			"aws_region": awsRegion,
		},
	}

	return terraformOptions

}

func TestInfra(t *testing.T) {
	t.Parallel()

	terraformDir := test_structure.CopyTerraformFolderToTemp(t, "../", "tests/terraform")

	defer test_structure.RunTestStage(t, "destroy", func() {
		terraformOptions := test_structure.LoadTerraformOptions(t, terraformDir)
		terraform.Destroy(t, terraformOptions)

	})

	test_structure.RunTestStage(t, "setup", func() {
		terraformOptionsInfra := configureTerraformOptions(t, terraformDir, "module.one")
		terraformOptionsConf := configureTerraformOptions(t, terraformDir, "module.two")

		test_structure.SaveTerraformOptions(t, terraformDir, terraformOptionsInfra)

		test_structure.SaveTerraformOptions(t, terraformDir, terraformOptionsConf)

        terraform.InitAndApply(t, terraformOptionsInfra)
		terraform.InitAndApply(t, terraformOptionsConf)
	})
	test_structure.RunTestStage(t, "validate", func() {
		terraformOptions := test_structure.LoadTerraformOptions(t, terraformDir)
		testHello(t, terraformOptions)

	})
}

func testHello(t *testing.T, terraformOptions *terraform.Options) {
   fmt.Printf("Hello")
}


Is there any way to target like when I apply ?

Thanks;

Answers

I think there are a couple issues here:

  1. In the setup step, you're calling SaveTerraformOptions twice, but what you have to realize is that the second call is overwriting the first one!
  2. In the destroy step, you call LoadTerraformOptions and Destroy just once, so even if you had both terraform.Options structs, you'd still only be running destroy on one of them.

I think to fix this, in the setup step, you'll to call SaveTestData directly (SaveTerraformOptions is just a wrapper for this method) with different paths:

test_structure.SaveTestData(t, test_structure.FormatTestDataPath(terraformDir, "TerraformOptionsInfra.json"), terraformOptionsInfra)
test_structure.SaveTestData(t, test_structure.FormatTestDataPath(terraformDir, "TerraformOptionsConf.json"), terraformOptionsConf)

And then you'll want two destroy steps (e.g., destroy_infra, destroy_conf), and each should use LoadTestData to get your data back and run Destroy on it:

defer test_structure.RunTestStage(t, "destroy_infra", func() {
  var terraformOptionsInfra *terraform.Options
  test_structure.LoadTestData(t, test_structure.FormatTestDataPath(terraformDir, "TerraformOptionsInfra.json"), terraformOptionsInfra)
  terraform.Destroy(t, terraformOptionsInfra)
})

defer test_structure.RunTestStage(t, "destroy_conf", func() {
  var terraformOptionsConf *terraform.Options
  test_structure.LoadTestData(t, test_structure.FormatTestDataPath(terraformDir, "TerraformOptionsConf.json"), terraformOptionsConf)
  terraform.Destroy(t, terraformOptionsConf)
})
Posted on by Yevgeniy Brikman