Terratest multiple targets

2k views Asked by At

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;

2

There are 2 answers

2
Yevgeniy Brikman On

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)
})
0
Ahmed-F On

I finally managed to get it working. Using @yevgeniy idea, I came up with following code.

    package test
    
    import (
                "fmt"
                 "time"
                "os"
                "testing"
                "net/http"
                "log"
                "io/ioutil"
    
                "github.com/gruntwork-io/terratest/modules/terraform"
                "github.com/gruntwork-io/terratest/modules/retry"
    
                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() {
            terraformOptionsInfra := configureTerraformOptions(t, terraformDir, "module.infra")
            terraformOptionsConf := configureTerraformOptions(t, terraformDir, "module.conf")
            terraform.Destroy(t, terraformOptionsConf)
            terraform.Destroy(t, terraformOptionsInfra)
        })
    
        test_structure.RunTestStage(t, "setup", func() {
            terraformOptionsInfra := configureTerraformOptions(t, terraformDir, "module.infra")
            terraformOptionsConf := configureTerraformOptions(t, terraformDir, "module.conf")
    
            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")
}

I hope this can help other people.