Add resource tests #
This page describes how to add tests to a new resource in the google
or google-beta
Terraform provider.
For more information about testing, see the official Terraform documentation.
Before you begin #
- Determine whether your resources is using MMv1 generation or handwritten.
- If you are not adding tests to an in-progress PR, ensure that your
magic-modules
,terraform-provider-google
, andterraform-provider-google-beta
repositories are up to date.cd ~/magic-modules git checkout main && git clean -f . && git checkout -- . && git pull cd $GOPATH/src/github.com/hashicorp/terraform-provider-google git checkout main && git clean -f . && git checkout -- . && git pull cd $GOPATH/src/github.com/hashicorp/terraform-provider-google-beta git checkout main && git clean -f . && git checkout -- . && git pull
Add a create test #
A create test is a test that creates the target resource and immediately destroys it.
Note: All resources should have a “basic” create test, which uses the smallest possible number of fields. Additional create tests can be used to ensure all fields on the resource are used in at least one test.
- Using an editor of your choice, create a
*.tf.erb
file inmmv1/templates/terraform/examples/
. The name of the file should include the service name, resource name, and a descriptor. For example,compute_subnetwork_basic.tf.erb
. - Write the Terraform configuration for your test. This should include all of the required dependencies. For example,
google_compute_subnetwork
has a dependency ongoogle_compute_network
:resource "google_compute_subnetwork" "primary" { name = "my-subnet" ip_cidr_range = "10.1.0.0/16" region = "us-central1" network = google_compute_network.network.name } resource "google_compute_network" "network" { name = "my-network" auto_create_subnetworks = false }
- If beta-only fields are being tested:
- Add
provider = google-beta
to every resource in the file.
- Add
- Modify the configuration to use templated values.
- Replace the id of the primary resource you are testing with
<%= ctx[:primary_resource_id] %>
. - Replace fields that are identifiers, like
id
orname
, with an appropriately named variable. For example,<%= ctx[:vars]['subnetwork_name'] %>
. - The resulting configuration for the above example would look like this:
resource "google_compute_subnetwork" "<%= ctx[:primary_resource_id] %>" { name = "<%= ctx[:vars]['subnetwork_name'] %>" ip_cidr_range = "10.1.0.0/16" region = "us-central1" network = google_compute_network.network.name } resource "google_compute_network" "network" { name = "<%= ctx[:vars]['network_name'] %>" auto_create_subnetworks = false }
- Replace the id of the primary resource you are testing with
- Modify the relevant
RESOURCE_NAME.yaml
file under magic-modules/mmv1/products to include anexamples
block with your test. Thename
must match the name of your*.tf.erb
file. For example:examples: - !ruby/object:Provider::Terraform::Examples name: "compute_subnetwork_basic" primary_resource_id: "example" vars: subnetwork_name: "example-subnet" network_name: "example-network"
Warning: Values invars
must include a-
(or_
). They trigger the addition of atf-test
prefix, which the sweeper uses to clean them up after tests run.
- If beta-only fields are being tested:
- Add
min_version: beta
to theexamples
block inRESOURCE_NAME.yaml
.
- Add
This section assumes you’ve used the Add a resource guide to create your handwritten resource, and you have a working MMv1 config.
Note: If not, you can create one now, or skip this guide and construct the test by hand. Writing tests by hand can sometimes be a better option if there is a similar test you can copy from.
- Add the test in MMv1. Repeat for all the create tests you will need.
- Generate the beta provider.
- From the beta provider, copy and paste the generated
*_generated_test.go
file into the appropriate service folder insidemagic-modules/mmv1/third_party/terraform/services
as a new file call*_test.go
. - Modify the tests as needed.
- Replace all occurrences of
github.com/hashicorp/terraform-provider-google-beta/google-beta
withgithub.com/hashicorp/terraform-provider-google/google
- Remove the comments at the top of the file.
- Remove the
Example
suffix from all function names. - If beta-only fields are being tested, do the following:
- Change the file suffix to
.go.erb
- Add
<% autogen_exception -%>
to the top of the file - Wrap each beta-only test in a separate version guard:
<% unless version == 'ga' -%>...<% else -%>...<% end -%>
- Change the file suffix to
- Replace all occurrences of
Add an update test #
An update test is a test that creates the target resource and then makes updates to fields that are updatable. Updatable fields are fields that can be updated without recreating the entire resource; that is, they are not marked immutable
in MMv1 or ForceNew
in handwritten code.
Note: All updatable fields must be covered by at least one update test. In most cases, only a single update test is needed to test all fields at once.
- Generate the beta provider.
- From the beta provider, copy and paste the generated
*_generated_test.go
file into the appropriate service folder insidemagic-modules/mmv1/third_party/terraform/services
as a new file call*_test.go
. - Using an editor of your choice, delete the
*DestroyProducer
function, and all but one test. The remaining test should be the “full” test, or if there is no “full” test, the “basic” test. This will be the starting point for your new update test. - Modify the
TestAcc*
test function to support updates.- Change the suffix of the test function to
_update
. - Copy the 2
TestStep
blocks and paste them immediately after, so that there are 4 total test steps. - Change the suffix of the first
Config
value to_full
(or_basic
). - Change the suffix of the second
Config
value to_update
. - The resulting test function would look similar to this:
func TestAccPubsubTopic_update(t *testing.T) { ... acctest.VcrTest(t, resource.TestCase{ ... Steps: []resource.TestStep{ { Config: testAccPubsubTopic_full(...), }, { ... }, { Config: testAccPubsubTopic_update(...), }, { ... }, }, }) }
- Change the suffix of the test function to
- Modify the
testAcc*
Terraform template function to support updates.- Copy the template function and paste it immediately after so that there are 2 template functions.
- Change the suffix of the first template function to
_full
(or_basic
). - Change the suffix of the second template function to
_update
. - The resulting template functions would look similar to this:
func testAccPubsubTopic_full(...) string { ... } func testAccPubsubTopic_update(...) string { ... }
- Modify the test as needed.
- Replace all occurrences of
github.com/hashicorp/terraform-provider-google-beta/google-beta
withgithub.com/hashicorp/terraform-provider-google/google
- Modify the template function ending in
_update
so that updatable fields are changed or removed. This may require additions to thecontext
map in the test function. - Remove the comments at the top of the file.
- If beta-only fields are being tested, do the following:
- Change the file suffix to
.go.erb
- Add
<% autogen_exception -%>
to the top of the file - Wrap each beta-only test in a separate version guard:
<% unless version == 'ga' -%>...<% else -%>...<% end -%>
- In each beta-only test, ensure that the TestCase sets
ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t)
- In each beta-only test, ensure that all Terraform resources in all configs have
provider = google-beta
set
- Change the file suffix to
- Replace all occurrences of
- Using an editor of your choice, open the existing
*_test.go
or*_test.go.erb
file in the appropriate service folder insidemagic-modules/mmv1/third_party/terraform/services
which contains your create tests. - Copy the
TestAcc*
test function for the existing “full” test. If there is no “full” test, use the “basic” test. This will be the starting point for your new update test. - Modify the test function to support updates.
- Change the suffix of the test function to
_update
. - Copy the 2
TestStep
blocks and paste them immediately after, so that there are 4 total test steps. - Change the suffix of the second
Config
value to_update
. - The resulting test function would look similar to this:
func TestAccPubsubTopic_update(t *testing.T) { ... acctest.VcrTest(t, resource.TestCase{ ... Steps: []resource.TestStep{ { Config: testAccPubsubTopic_full(...), }, { ... }, { Config: testAccPubsubTopic_update(...), }, { ... }, }, }) }
- Change the suffix of the test function to
- Add a Terraform template function to support updates.
- Copy the full (or basic)
testAcc*
template function. - Change the suffix of the new template function to
_update
. - The new template function would look similar to this:
func testAccPubsubTopic_update(...) string { ... }
- Copy the full (or basic)
- Modify the test as needed.
- Modify the new template function so that updatable fields are changed or removed. This may require additions to the
context
map in the test function. - Remove the comments at the top of the file.
- If beta-only fields are being tested, do the following:
- Change the file suffix to
.go.erb
- Add
<% autogen_exception -%>
to the top of the file - Wrap each beta-only test in a separate version guard:
<% unless version == 'ga' -%>...<% else -%>...<% end -%>
- In each beta-only test, ensure that the TestCase sets
ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t)
- In each beta-only test, ensure that all Terraform resources in all configs have
provider = google-beta
set
- Change the file suffix to
- Modify the new template function so that updatable fields are changed or removed. This may require additions to the
Add unit tests #
A unit test verifies functionality that is not related to interactions with the API, such as diff suppress functions), validation functions, CustomizeDiff functions, and so on.
Unit tests should be added to the appropriate folder in magic-modules/mmv1/third_party/terraform/services
in the file called resource_PRODUCT_RESOURCE_test.go
. (You may need to create this file if it does not already exist. Replace PRODUCT with the product name and RESOURCE with the resource name; it should match the name of the generated resource file.)
Unit tests should be named like TestFunctionName
- for example, TestDiskImageDiffSuppress
would contain tests for the DiskImageDiffSuppress
function.
Example:
func TestSignatureAlgorithmDiffSuppress(t *testing.T) {
cases := map[string]struct {
Old, New string
ExpectDiffSuppress bool
}{
"ECDSA_P256 equivalent": {
Old: "ECDSA_P256_SHA256",
New: "EC_SIGN_P256_SHA256",
ExpectDiffSuppress: true,
},
// Additional cases excluded for brevity
}
for tn, tc := range cases {
if signatureAlgorithmDiffSuppress("signature_algorithm", tc.Old, tc.New, nil) != tc.ExpectDiffSuppress {
t.Errorf("bad: %s, %q => %q expect DiffSuppress to return %t", tn, tc.Old, tc.New, tc.ExpectDiffSuppress)
}
}
}