Cheat notes · Module 06 · Safe change
Tests, checks and a pipeline on every pull request
A five-minute review for when you have done this module and want it back in your head. Open the full module for the steps and the lab, or the full text to print.
The idea
Some things can be proven from the files alone: format, validity, tests against a fake provider, and policy. A plan needs the real state and API, so it is not in a pull request workflow that cannot reach them. check blocks warn; validations and tests block.
Remember
terraform testruns*.tftest.hcl; eachrunplans the module and checksassertconditions.mock_provider "kubernetes" {}: no cluster, no credentials; computed values are invented.expect_failures = [var.environment]: passes only if that validation refuses the input.checkblock:Warning: Check block assertion failed, and the plan carries on.- CI jobs:
static(fmt,init -backend=false -lockfile=readonly, validate) per environment,test,policy(conftest on the HCL). - A module's own lock file is ignored by Git: a reusable module does not pin exact versions.
Pitfalls
- All checks green while a rule is broken: a rule that has no test exists only in people's heads.
- A new test that has never failed may assert nothing. Make it fail once for the reason it was written.
- Expecting CI to catch a destroy: without a plan job, only the person who pastes the plan sees it.
Commands
terraform test | Run the module's tests |
terraform fmt -check -recursive | Fail on unformatted files |
terraform init -backend=false -lockfile=readonly | Init without state; fail if the lock file is wrong |
docker run --rm -v "$PWD:/project" -w /project openpolicyagent/conftest:v0.71.1 test --parser hcl2 --ignore '\.terraform' -p policy envs modules | The policy, on the files |
gh pr checks --watch | Wait for the pull request's checks |
gh run view --log-failed | Why a check failed |
modules/team-namespace/tests/unit.tftest.hcl
mock_provider "kubernetes" {}
variables {
team = "checkout"
environment = "dev"
}
run "deployer_cannot_read_secrets" {
command = plan
assert {
condition = !contains(flatten([for r in kubernetes_role_v1.deployer.rule : r.resources]), "secrets")
error_message = "The deployer role must not include secrets."
}
}
Test yourself
Answer in your head first, then open the answer.
What does a mocked test prove, and what not?
Your own expressions and defaults; nothing about what the API will answer.
A check assertion fails during apply. What happens?
A warning; the apply completes.
Why is there no plan job in this workflow?
The runner cannot reach the cluster or the state store.
Where module 06 leaves you: modules/team-namespace/tests/unit.tftest.hcl has four run blocks and terraform test passes. envs/dev and envs/prod each have a check block. .github/workflows/terraform.yaml runs three jobs on pull requests; none of them applies anything. One pull request has gone through it.