Terraform
Overview
This guide helps you migrate a Terraform provider's acceptance testing dependencies from SDKv2 to the plugin testing module. We recommend migrating to terraform-plugin-testing to take advantage of new features of the testing module and to avoid importing the SDKv2 for providers that are built on the plugin Framework.
This guide provides information and examples for most common use cases, but it does not discuss every nuance of migration. You can ask additional migration questions in the HashiCorp Discuss forum. To request additions or updates to this guide, submit issues or pull requests to the terraform-plugin-testing
repository.
Migration steps
Take the following steps when you migrate a provider's acceptance tests from SDKv2 to the testing module.
Change all instances of the following Go import statements in *_test.go
files:
Original Import | Migrated Import |
---|---|
github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest | github.com/hashicorp/terraform-plugin-testing/helper/acctest |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource | github.com/hashicorp/terraform-plugin-testing/helper/resource |
github.com/hashicorp/terraform-plugin-sdk/v2/terraform | github.com/hashicorp/terraform-plugin-testing/terraform |
If the provider implements terraform-plugin-sdk based state migration unit testing with github.com/hashicorp/terraform-plugin-sdk/v2/terraform.InstanceState
, this must remain with the original import since it is testing terraform-plugin-sdk functionality.
Verify if the TestStep
type PlanOnly
field is enabled in any tests where the final TestStep
is intentionally changing the provider setup to ensure schema changes (e.g. state upgrades or SDK to framework migrations) cause no plan differences. In those tests, replace PlanOnly
with ConfigPlanChecks
containing a PreApply
check of plancheck.ExpectEmptyPlan()
instead:
resource.Test(t, resource.TestCase{
// ...
Steps: []resource.TestStep{
{ /* ... */ },
{
// ...
// The below replacing PlanOnly: true
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
},
},
})
Change all instances of the following in non-test *.go
files:
Original Reference | Migrated Reference |
---|---|
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.NonRetryableError | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.NonRetryableError |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.NotFoundError | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.NotFoundError |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.PrefixedUniqueId | github.com/hashicorp/terraform-plugin-sdk/v2/helper/id.PrefixedUniqueId |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.Retry | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.Retry |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.RetryableError | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.RetryableError |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.RetryContext | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.RetryContext |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.RetryError | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.RetryError |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.RetryFunc | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.RetryFunc |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.StateChangeConf | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.StateChangeConf |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.StateRefreshFunc | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.StateRefreshFunc |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.TimeoutError | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.TimeoutError |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.UnexpectedStateError | github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry.UnexpectedStateError |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.UniqueId | github.com/hashicorp/terraform-plugin-sdk/v2/helper/id.UniqueId |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.UniqueIdPrefix | github.com/hashicorp/terraform-plugin-sdk/v2/helper/id.UniqueIdPrefix |
github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource.UniqueIDSuffixLength | github.com/hashicorp/terraform-plugin-sdk/v2/helper/id.UniqueIDSuffixLength |
Get and download the latest version of terraform-plugin-testing:
$ go get github.com/hashicorp/terraform-plugin-testing@latest
Clean up go.mod
:
$ go mod tidy
Verify that the tests are working as expected.
Troubleshooting
flag redefined Panic
This panic occurs when your provider code imports both the github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource
and github.com/hashicorp/terraform-plugin-testing/helper/resource
packages because they contain a duplicate TestMain
function:
panic: XXX flag redefined: sweep
goroutine 1 [running]:
flag.(*FlagSet).Var(0x14000030240, {0x10132b6d8, 0x140002219c0}, {0x10103ad88, 0x5}, {0x10105d47b, 0x29})
/usr/local/go/src/flag/flag.go:982 +0x2a4
flag.(*FlagSet).StringVar(...)
/usr/local/go/src/flag/flag.go:847
flag.(*FlagSet).String(0x1400031fb98?, {0x10103ad88, 0x5}, {0x0, 0x0}, {0x10105d47b, 0x29})
/usr/local/go/src/flag/flag.go:860 +0x98
flag.String(...)
/usr/local/go/src/flag/flag.go:867
github.com/hashicorp/terraform-plugin-testing/helper/resource.init()
/XXX/go/pkg/mod/github.com/hashicorp/terraform-plugin-testing@v1.1.0/helper/resource/testing.go:53 +0x44
Remove imports of github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource
to resolve the issue. terraform-plugin-sdk version 2.26.0 introduced separate packages, github.com/hashicorp/terraform-plugin-sdk/v2/helper/id
and github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry
, which contain all non-testing functionality.
Failed to marshal state to json
This error can occur when your testing includes PlanOnly: true
in final TestStep
that is intentionally changing the provider setup to ensure schema changes (e.g. state upgrades or SDK to framework migrations) cause no plan differences:
Failed to marshal state to json: schema version 0 for examplecloud_thing.test in state does not match version 1 from the provider
# or in the case of removed attributes between provider versions:
Failed to marshal state to json: unsupported attribute
In those tests, replace PlanOnly
with ConfigPlanChecks
containing a PreApply
check of plancheck.ExpectEmptyPlan()
instead:
resource.Test(t, resource.TestCase{
// ...
Steps: []resource.TestStep{
{ /* ... at least one prior step ... */ },
{
// ...
// Replacing PlanOnly: true
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
},
},
})