TerraformPilot

Infrastructure as Code

Terratest v2.0.0: Modular Go Libraries for Testing Terraform and Kubernetes Infrastructure

Terratest v2.0.0 splits into 16 Go modules under /v2 import paths, trims dependencies, and changes two Kubernetes behaviors. Upgrade notes inside.

LLuca Berton5 min read

Introduction

#

gruntwork-io/terratest has shipped its first stable v2 release, tagged as modules/core/v2.0.0. All 16 modules move in lockstep to v2, each installable independently via its own go.mod. This is the first stable release after the beta series; there is no previously tracked stable version on this site, so this article covers the full v1-to-v2 migration plus what changed since beta.2.

The headline change is structural, not feature-driven: Terratest is now 16 separate Go modules instead of one monolith, so a test only pulls in the SDK dependencies of the modules it actually imports.

What Is New

#

Modular packaging

#

Every module now lives under github.com/gruntwork-io/terratest/modules/<name>/v2. A test that only drives Terraform no longer drags in AWS, Azure, GCP, or Kubernetes SDKs.

# v1 go.sum for the single terratest module: 675 lines
# v2 go.sum for terraform/v2 alone: 77 lines

A CI check now enforces an explicit allowlist of dependencies between modules, so a stray import can't silently pull one module's dependencies into another.

Package renames

#

Three packages drop their hyphens in both import path and Go identifier:

  • http-helper -> httphelper
  • dns-helper -> dnshelper
  • test-structure -> teststructure

Utility packages consolidated

#

random, files, logger, shell, retry, and testing now live in core/v2.

Deprecated helpers removed

#

Code calling terraform.Apply must move to terraform.ApplyContext(t, ctx, ...), the replacement v1's deprecation warnings already pointed to.

// v1
terraform.Apply(t, terraformOptions)
 
// v2
terraform.ApplyContext(t, ctx, terraformOptions)

Packages removed entirely

#

collections, environment, git, version-checker, slack, oci, and the two cmd/ binaries are gone. v1.0.1's deprecation notices name replacements for the first five.

Save/Load helpers relocated

#

Eight teststructure.{Save,Load}* helpers move beside the type they handle, into aws, k8s, packer, and ssh, with the same function signatures.

Two Kubernetes behavior changes (compile-clean, read before upgrading)

#

These compile without error under v2, so they're easy to miss:

  • Node address preference: k8s.FindNodeHostnameContextE and k8s.GetServiceEndpointContextE (for a NodePort service) now prefer the node's ExternalIP when the cluster records one. On EKS this is the public IP, so the common path no longer needs ec2:DescribeInstances IAM permissions.
  • KubectlOptions with a RestConfig can't serialize: MarshalJSON now returns k8s.ErrRestConfigNotSerializable instead of silently dropping the config and falling back to the ambient kubeconfig, which would have authenticated a reloaded test against the wrong cluster. v1 failed here too, just with an unclear error.

New GCP resource readers

#

Since beta.2, the gcp module can read back the live settings of 82 kinds of Google Cloud resources, letting a test assert on what Terraform actually created, not just that the resource exists. Each resource gets three forms: fail-the-test, return-the-error, and a WithClient variant for unit tests with injected clients and no credentials.

bucket := gcp.GetStorageBucketAttrs(t, ctx, bucketName)
assert.True(t, bucket.UniformBucketLevelAccess.Enabled)

Coverage spans compute/networking (disks, instance templates, VPCs, load balancer pieces, Cloud Armor), storage/data (Cloud Storage, BigQuery, Cloud SQL, Spanner, Bigtable, Firestore, AlloyDB, Dataproc, Dataflow, Composer, Dataplex), containers/serverless (GKE, Cloud Run, Cloud Functions, Workflows, Cloud Build, Cloud Deploy, Artifact Registry), identity/security (service accounts, workload identity, Secret Manager, KMS, Certificate Manager), operations (log sinks, alert policies, SLOs, dashboards), and messaging/DNS/AI (Pub/Sub, Cloud DNS, Healthcare, Document AI, Dialogflow CX). No new dependencies were added for this: gcp/v2's go.sum stays at 267 lines.

Other changes since beta.2

#
  • Kubernetes client libraries bumped to v0.37.0, growing k8s/v2's go.sum from 160 to 178 lines (PR #1889).
  • A full v2 migration guide is now published on the docs site (PR #1884).

Fixes since v1.0.1

#
  • random.UniqueID no longer collides between calls made in the same instant (PR #1860).
  • Dependencies bumped to resolve known CVEs (PR #1861).
  • ssh.SaveSSHKeyPair no longer writes the private key to the test log.
  • Saved test data now written with 0o600 permissions instead of 0o644.
  • core/teststate stops after a fatal error instead of leaving an empty file behind on a marshal failure (PR #1880).
  • An IPv6 service endpoint fix is referenced in the release notes but the description is cut off in the source; check the release page for the full text.

Upgrade Steps

#

v1 receives security fixes only, for 12 months from this release, so plan the move to v2 rather than staying pinned indefinitely.

  1. Rewrite import paths. The rewriting imports guide ships the sed commands and flags the cases a blind find-and-replace gets wrong:
# Example pattern from the migration guide family - verify against the
# official rewriting-imports page before running on a real repo
find . -name '*.go' -exec sed -i \
  -e 's#gruntwork-io/terratest/modules/terraform"#gruntwork-io/terratest/modules/terraform/v2"#g' \
  {} +
  1. Update go.mod to pull only the modules a given test package actually needs, instead of the single v1 module:
go get github.com/gruntwork-io/terratest/modules/terraform/v2@v2.0.0
go get github.com/gruntwork-io/terratest/modules/k8s/v2@v2.0.0
go mod tidy
  1. Replace renamed packages and identifiers: http-helper -> httphelper, dns-helper -> dnshelper, test-structure -> teststructure.

  2. Replace any remaining terraform.Apply calls with terraform.ApplyContext(t, ctx, ...).

  3. If the removed packages (collections, environment, git, version-checker, slack, oci, cmd/) are in use, check v1.0.1's deprecation notices for named replacements before dropping the import.

  4. For Kubernetes tests, review the two behavior changes above - they compile cleanly but change runtime results. The behavior changes page covers both.

  5. Run the build; the Go compiler surfaces every remaining break (moved teststructure.{Save,Load}* helpers, consolidated utility packages, etc.) except the two Kubernetes behavior changes called out above.

go build ./...
go vet ./...

Verify

#

After rewriting imports and updating go.mod, confirm the module resolves to v2 and the test suite still passes:

go list -m all | grep terratest
go test ./... -run TestYourTerraformTest -v

For Kubernetes-facing tests specifically, re-run any test that calls k8s.FindNodeHostnameContextE or hits a NodePort service through k8s.GetServiceEndpointContextE, and confirm the returned address is the expected ExternalIP rather than an internal one the old IAM-based lookup used to produce.

Conclusion

#

Terratest v2.0.0 is primarily a packaging change: 16 independently installable modules under /v2, a dependency allowlist enforced in CI, and a much smaller go.sum for narrow-scope tests. The Go compiler catches almost every breaking change during the import rewrite; the two Kubernetes behavior changes around ExternalIP preference and RestConfig serialization are the ones worth reading about before upgrading a cluster test. GCP users gain 82 new resource readers for asserting on actual infrastructure state. v1 stays on security-fix-only support for 12 months from this release, so teams should budget the migration rather than treat it as optional.

#Terratest#Go#Terraform#Kubernetes#Google Cloud#AWS

Share this article