Skip to content

How to use go's TestMain with terratest? #1047

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

Open
michalschott opened this issue Jan 12, 2022 · 3 comments
Open

How to use go's TestMain with terratest? #1047

michalschott opened this issue Jan 12, 2022 · 3 comments
Labels
Core enhancement New feature or request needs design We need to flesh out the design before we can resolve the issue

Comments

@michalschott
Copy link

michalschott commented Jan 12, 2022

I have very similar problem described here.

My use case is I'd like to pre-create few resources (VPC, Route53 zone) so other tests can use these.

So far I have managed to do this:

func TestMain(m *testing.M) {
	t := &testing.T{}

	// create vpc
	vpcTestSource := test_structure.CopyTerraformFolderToTemp(t, "../../", "modules/aws/vpc")
	vpcTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
		TerraformDir: vpcTestSource,
		Vars: map[string]interface{}{
                  ...
		},
		EnvVars: map[string]string{
			"AWS_DEFAULT_REGION": awsRegion,
		},
	})
	defer terraform.Destroy(t, vpcTerraformOptions)
	terraform.InitAndApplyAndIdempotent(t, vpcTerraformOptions)
}

Altho if terraform apply in above snippet fails, looks like test is waiting for timeout actually to happen. Suspect it happens due to "custom" testing.T object.

@yorinasub17 yorinasub17 added Core enhancement New feature or request needs design We need to flesh out the design before we can resolve the issue labels Jan 13, 2022
@yorinasub17
Copy link
Contributor

yorinasub17 commented Jan 13, 2022

Unfortunately this is currently not a supported mode of operation in terratest, primarily because we rely on the t struct to do various things like logging and test failing on errors. We will need a version of each function that is optimized for testing.M instead of testing.T to make this work.

We are a bit buried to take this on, so I suspect this won't get implemented in the short term, unless someone from the community is willing to take it.

@michalschott
Copy link
Author

michalschott commented Jan 17, 2022

@yorinasub17 I have been using below snippet (slightly modified from what I have originally pasted above) and it runs flawlessly so far:

func TestMain(m *testing.M) {
	t := &testing.T{}

	// create vpc
	fmt.Printf("Preparing VPC %s\n", testSuite.stage)
	vpcTestSource := test_structure.CopyTerraformFolderToTemp(t, "../../", "modules/aws/networking")
	vpcTerraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
		TerraformDir: vpcTestSource,
		Vars: map[string]interface{}{
			...
		},
		EnvVars: map[string]string{
			...
		},
	})
	defer terraform.Destroy(t, vpcTerraformOptions)
	if _, err := terraform.InitAndApplyAndIdempotentE(t, vpcTerraformOptions); err != nil {
		terraform.Destroy(t, vpcTerraformOptions)
		os.Exit(1)
	}

	// assertions for VPC module
      
	// run all the tests
	m.Run()
}

I was also looking at beforeEach approach to create VPCs, but this does not scale well in my use case since VPC creation with all dependencies takes approx 5-8 minutes.

@yorinasub17
Copy link
Contributor

I have been using below snippet (slightly modified from what I have originally pasted above) and it runs flawlessly so far:

If you have a working solution, then that's great! Does that solve your original problem of apply hanging when there is an error?

I was also looking at beforeEach approach to create VPCs, but this does not scale well in my use case since VPC creation with all dependencies takes approx 5-8 minutes.

Ah, FWIW, the main way the Gruntwork team addresses this is by using subtests. It's not ideal due to the various gotchas around t.Parallel, but it works for the most part:

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

    vpcOpts := createVPCTerraforOptions(t)
    defer terraform.Destroy(t, vpcOpts)
    terraform.InitAndApply(t, vpcOpts)

    // We wrap all the subtests in a synchronous grouped test (not calling t.Parallel)
    // so that all the subtests in the group finish before returning control to the main thread.
    t.Run("group", func(t *testing.T) {
        t.Run("TestOneThatNeedsVPC", func(t *testing.T) {
            t.Parallel()
            testOneThatNeedsVPC(t, vpcOpts)
        })
        t.Run("TestTwoThatNeedsVPC", func(t *testing.T) {
            t.Parallel()
            testTwoThatNeedsVPC(t, vpcOpts)
        })
        // ... and so on ...
    })
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Core enhancement New feature or request needs design We need to flesh out the design before we can resolve the issue
Projects
None yet
Development

No branches or pull requests

2 participants