Terraform Automated Testing
All of our Terraform modules have automated tests. We have two sets of checks:
- The first set of checks is executed through the feature-branch workflow, which can be found here This workflow generates some documentation and performs basic sanity checks, including linting and formatting. These checks are lightweight and can be executed without requiring any special permissions. Consequently, they are automatically run on every commit. Before committing and pushing your changes, you can and should run this set of checks locally by executing the following command on your host
make precommit/terraform
Running these checks locally incorporates all the required changes that otherwise would block your PR.
- The second set of checks consists of Terraform integration tests that validate the functionality and integration of the module. These tests are performed using the
terratest
library, specifically designed for infrastructure testing, and do more in-depth integration tests of module functionality. Unlike the first set of checks, these integration tests are executed only on request, and only by authorized contributors. We use ChatOps to trigger this workflow.
Philosophy of Terraform Integration Testing
At a minimum, we ensure that all of our modules cleanly plan
, apply
and destroy
. This catches 80% of the problems with only 20% of the effort. We also test than then the enabled
input is set to false
, no resources are created.
Ideally we would like to test that the resources are properly created, but often this is difficult to verify programmatically, in which case we settle for spot checking that the dynamic outputs match our expectations. At the same time, we do not want to waste effort retesting what has already been tested by HashiCorp and their providers. For example, we have our terraform-aws-s3-bucket
module that creates an S3 bucket. We don't need to test that a bucket is created; we assume that would be caught by the upstream terraform tests. But we do want to test that the bucket name is what we expect it to be, since this is something under our control.
Using ChatOps To Trigger Integration Tests
In addition to automatic triggers, tests can be run on demand via "ChatOps". (You will need to have at least triage
level of access to a repo to use ChatOps commands.) Typically, tests are run by a CloudPosse contributor or team member as part of a PR review.
Tests are initiated by posting GitHub comments on the PR. Currently supported commands are the following:
Command | Description |
---|---|
/terratest | Run the terratest integration tests in test/src |
Terraform tests run against our testing infrastructure that we host in an isolated account on AWS, strictly for the purposes of testing infrastructure.
ChatOps is powered by GitHub Actions and the slash-dispatch-command.
The terratest workflow is defined in the cloudposse/actions
repository. The benefit with this is that we have one place to control the testing
workflow for all of our hundreds of terraform modules. The downside, however, with dispatched workflows is that the workflows always run from the main
branch.
Manually triggering a shared workflow
Here's a list a workflows you might want to trigger manually should things go wrong on GitHub side or with our configuration.
feature-branch
can be triggered anytime by labeling/unlabeling PR with any label.release-branch
is the same to creating a GH release manually. We have created a complimentary workflowrelease-published
for this case: it will fulfill the missing parts once you create a release manually. Note that you are skipping tests before release in this case.scheduled
can be triggered anytime from GitHub UI, it has a workflow_dispatch trigger for this purpose.
ChatOps Configuration
If you're a contributor who wants to intialize one of our terraform modules, this is the process. Note, if a repo has already been configured for chatops, there's no need to proceed with these steps.
To initialize one of our modules with chatops, run the following commands:
git clone
the terraform module repositorycd $repo
to enter the repository directorymake init
to initialize the build-harnessgit add *
to add the changes- Add the build badge to the
README.yaml
under thebadges
section. make readme
to rebuild theREADME.md
(remember, never edit theREADME.md
manually since it's generated from theREADME.yaml
)- Open up a Pull Request with the changes. Here is a good example.
- Request a Code Review in the
#pr-reviews
Slack channel (and big thanks for your contribution!)