'Terratest - How to pass Terraform outputs between functions
I tried to use 'test_structure.SaveTerraformOptions' but it doesn't save resources IDs. For example, I'm running 2 modules - Module 1 creating the networking and the subnets, module 2 needs module's 1 subnets ids. How can I pass this info between them?
When I'm running both functions in the same 'test_structure.RunTestStage' I am able to pass resource id from one function to another, but it doesn't test the first function and doesn't destroy at the end.
I am going to write a helper function that will only load everything and the other functions will do the testing. Maybe this will help.
However, what is the best practice to this?
This is my code:
package test
import (
"testing"
//"github.com/gruntwork-io/terratest/modules/random"
"github.com/gruntwork-io/terratest/modules/azure"
"github.com/gruntwork-io/terratest/modules/terraform"
test_structure "github.com/gruntwork-io/terratest/modules/test-structure"
"github.com/stretchr/testify/assert"
)
// An example of how to test the simple Terraform module in examples/terraform-basic-example using Terratest.
func TestRunAll(t *testing.T) {
t.Parallel()
environmentName := "dev"
projectName := "toha"
rgName := environmentName + "-" + projectName + "-rg"
subscriptionID := "96b72f1a-1bdc-4fc7-b971-05e7cea7d850"
rg_net := test_structure.CopyTerraformFolderToTemp(t, "../", "001_networking")
test_structure.RunTestStage(t, "test_azure_resource_group", func() {
terraformOptions := testAzureResourceGroup(t, rgName, subscriptionID)
test_structure.SaveTerraformOptions(t, rg_net, terraformOptions)
testTerraformAzureFunctionApp(t, rgName, terraformOptions)
terraform.Destroy(t, terraformOptions)
})
}
func testAzureResourceGroup(t *testing.T, rgName string, subscriptionID string) *terraform.Options {
//uniquePostfix := strings.ToLower(random.UniqueId())
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../001_networking",
Vars: map[string]interface{}{
"rg_name": rgName,
},
VarFiles: []string{"../../environments/dev/vars.tfvars"},
// Disable colors in Terraform commands so its easier to parse stdout/stderr
NoColor: true,
})
terraform.InitAndApply(t, terraformOptions)
rg_name_out := terraform.Output(t, terraformOptions, "rg-name")
assert.Equal(t, rgName, rg_name_out)
return terraformOptions
}
func testTerraformAzureFunctionApp(t *testing.T, rgName string, netOpts *terraform.Options) {
azurePortalIPRange := []string{"61.100.129.0/24"}
subnet_1 := terraform.Output(t, netOpts, "azurerm_subnet_1")
subnet_2 := terraform.Output(t, netOpts, "azurerm_subnet_2")
terraformOptions := &terraform.Options{
TerraformDir: "../002_function_app",
Vars: map[string]interface{}{
"subnet_id_1": subnet_1,
"subnet_id_2": subnet_2,
"rg_name": rgName,
"azure_portal_ip_range": azurePortalIPRange,
"cosmos_db_endpoint": "test",
"cosmos_db_password": "test",
},
VarFiles: []string{"../../environments/dev/vars.tfvars"},
}
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
resourceGroupName := terraform.Output(t, terraformOptions, "resource_group_name")
appName := terraform.Output(t, terraformOptions, "function_app_name")
appId := terraform.Output(t, terraformOptions, "function_app_id")
appDefaultHostName := terraform.Output(t, terraformOptions, "default_hostname")
appKind := terraform.Output(t, terraformOptions, "function_app_kind")
// website::tag::4:: Assert
assert.True(t, azure.AppExists(t, appName, resourceGroupName, ""))
site := azure.GetAppService(t, appName, resourceGroupName, "")
assert.Equal(t, appId, *site.ID)
assert.Equal(t, appDefaultHostName, *site.DefaultHostName)
assert.Equal(t, appKind, *site.Kind)
assert.NotEmpty(t, *site.OutboundIPAddresses)
assert.Equal(t, "Running", *site.State)
}
Solution 1:[1]
I think the best way you can use the test_structure is separate by stages (https://pkg.go.dev/github.com/gruntwork-io/terratest/modules/test-structure#RunTestStage):
Configure terratest, save the options for your specific configuration to terraform --> SETUP
test_structure.RunTestStage(t, "SETUP", func() { terraformOption := &terraform.Options{ TerraformDir: "your/path/here", } test_structure.SaveTerraformOptions(t, directory, terraformOption) terraform.InitAndApply(t, terraformOption) })
Destroy your infra at the end of the testing --> TEARDOWN
defer test_structure.RunTestStage(t, "TEARDOWN", func() { terraformOptions := test_structure.LoadTerraformOptions(t, directory) terraform.Destroy(t, terraformOptions) })
Your test cases --> TESTS
test_structure.RunTestStage(t, "TESTS", func() { terraformOption := test_structure.LoadTerraformOptions(t, "your/path/") // Your outputs resourceGroupName := terraform.Output(t, terraformOptions, "resource_group_name") appName := terraform.Output(t, terraformOptions, "function_app_name") appId := terraform.Output(t, terraformOptions, "function_app_id") // your functions // it can receive the outputs or anything t.Run("Test1", func(t *testing.T) { testAzureResourceGroup(t, resourceGroupName, subscriptionID) }) t.Run("Test2", func(t *testing.T) { testTerraformAzureFunctionApp(t, appId, appName) }) })
Microsoft have one example more explain https://docs.microsoft.com/en-us/azure/developer/terraform/best-practices-end-to-end-testing :)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Monse |