Skip to content

Commit aec7c3c

Browse files
authored
terraform test: allow computed/mocked values override during planning (#36227)
1 parent b59439b commit aec7c3c

File tree

20 files changed

+472
-36
lines changed

20 files changed

+472
-36
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: ENHANCEMENTS
2+
body: '`terraform test`: Test runs now support using mocked or overridden values during unit test runs (e.g., with command = "plan"). When override_during = "plan"'
3+
time: 2025-01-08T11:34:33.709443+01:00
4+
custom:
5+
Issue: "36227"

CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ ENHANCEMENTS:
66

77
* New command `modules -json`: Displays a full list of all installed modules in a working directory, including whether each module is currently referenced by the working directory's configuration. ([#35884](https://github.com/hashicorp/terraform/issues/35884))
88

9-
109
EXPERIMENTS:
1110

1211
Experiments are only enabled in alpha releases of Terraform CLI. The following features are not yet available in stable releases.

internal/command/test_test.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,25 @@ func TestTest_Runs(t *testing.T) {
219219
code: 0,
220220
},
221221
"mocking": {
222-
expectedOut: []string{"6 passed, 0 failed."},
222+
expectedOut: []string{"9 passed, 0 failed."},
223223
code: 0,
224224
},
225225
"mocking-invalid": {
226-
expectedErr: []string{"Invalid outputs attribute"},
227-
initCode: 1,
226+
expectedErr: []string{
227+
"Invalid outputs attribute",
228+
"The override_during attribute must be a value of plan or apply.",
229+
},
230+
initCode: 1,
231+
},
232+
"mocking-error": {
233+
expectedErr: []string{
234+
"Unknown condition value",
235+
"plan_mocked_overridden.tftest.hcl",
236+
"test_resource.primary[0].id",
237+
"plan_mocked_provider.tftest.hcl",
238+
"test_resource.secondary[0].id",
239+
},
240+
code: 1,
228241
},
229242
"dangling_data_block": {
230243
expectedOut: []string{"2 passed, 0 failed."},
@@ -1748,8 +1761,9 @@ Condition expression could not be evaluated at this time. This means you have
17481761
executed a %s block with %s and one of the values your
17491762
condition depended on is not known until after the plan has been applied.
17501763
Either remove this value from your condition, or execute an %s command
1751-
from this %s block.
1752-
`, "`run`", "`command = plan`", "`apply`", "`run`"),
1764+
from this %s block. Alternatively, if there is an override for this value,
1765+
you can make it available during the plan phase by setting %s in the %s block.
1766+
`, "`run`", "`command = plan`", "`apply`", "`run`", "`override_during =\nplan`", "`override_`"),
17531767
},
17541768
"unknown_value_in_vars": {
17551769
code: 1,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
terraform {
2+
required_providers {
3+
test = {
4+
source = "hashicorp/test"
5+
configuration_aliases = [test.primary, test.secondary]
6+
}
7+
}
8+
}
9+
10+
variable "instances" {
11+
type = number
12+
}
13+
14+
resource "test_resource" "primary" {
15+
provider = test.primary
16+
count = var.instances
17+
}
18+
19+
resource "test_resource" "secondary" {
20+
provider = test.secondary
21+
count = var.instances
22+
}
23+
24+
output "primary" {
25+
value = test_resource.primary
26+
}
27+
28+
output "secondary" {
29+
value = test_resource.secondary
30+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
terraform {
2+
required_providers {
3+
test = {
4+
source = "hashicorp/test"
5+
}
6+
}
7+
}
8+
9+
provider "test" {
10+
alias = "primary"
11+
}
12+
13+
provider "test" {
14+
alias = "secondary"
15+
}
16+
17+
variable "instances" {
18+
type = number
19+
}
20+
21+
variable "child_instances" {
22+
type = number
23+
}
24+
25+
resource "test_resource" "primary" {
26+
provider = test.primary
27+
count = var.instances
28+
}
29+
30+
resource "test_resource" "secondary" {
31+
provider = test.secondary
32+
count = var.instances
33+
}
34+
35+
module "child" {
36+
count = var.instances
37+
38+
source = "./child"
39+
40+
providers = {
41+
test.primary = test.primary
42+
test.secondary = test.secondary
43+
}
44+
45+
instances = var.child_instances
46+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
mock_provider "test" {
2+
alias = "primary"
3+
4+
mock_resource "test_resource" {
5+
defaults = {
6+
id = "aaaa"
7+
}
8+
}
9+
10+
override_resource {
11+
target = test_resource.primary
12+
values = {
13+
id = "bbbb"
14+
}
15+
}
16+
}
17+
18+
variables {
19+
instances = 1
20+
child_instances = 1
21+
}
22+
23+
// This test will fail because the plan command does not use the
24+
// overridden values for computed properties,
25+
// making the left-hand side of the condition unknown.
26+
run "test" {
27+
command = plan
28+
29+
assert {
30+
condition = test_resource.primary[0].id == "bbbb"
31+
error_message = "plan should not have the overridden value"
32+
}
33+
34+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
mock_provider "test" {
2+
alias = "secondary"
3+
4+
mock_resource "test_resource" {
5+
defaults = {
6+
id = "ffff"
7+
}
8+
}
9+
}
10+
11+
12+
variables {
13+
instances = 2
14+
child_instances = 1
15+
}
16+
17+
run "test" {
18+
command = plan
19+
20+
assert {
21+
condition = test_resource.secondary[0].id == "ffff"
22+
error_message = "plan should use the mocked provider value when override_during is plan"
23+
}
24+
25+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
mock_provider "test" {
2+
alias = "primary"
3+
override_during = baz // This should either be plan or apply, therefore this test should fail
4+
5+
mock_resource "test_resource" {
6+
defaults = {
7+
id = "aaaa"
8+
}
9+
}
10+
11+
override_resource {
12+
target = test_resource.primary
13+
values = {
14+
id = "bbbb"
15+
}
16+
}
17+
}
18+
19+
variables {
20+
instances = 1
21+
child_instances = 1
22+
}
23+
24+
run "test" {
25+
26+
assert {
27+
condition = test_resource.primary[0].id == "bbbb"
28+
error_message = "mock not applied"
29+
}
30+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
mock_provider "test" {
2+
alias = "primary"
3+
4+
mock_resource "test_resource" {
5+
defaults = {
6+
id = "aaaa"
7+
}
8+
}
9+
10+
override_resource {
11+
target = test_resource.primary
12+
override_during = plan
13+
values = {
14+
id = "bbbb"
15+
}
16+
}
17+
}
18+
19+
variables {
20+
instances = 1
21+
child_instances = 1
22+
}
23+
24+
run "test" {
25+
command = plan
26+
27+
assert {
28+
condition = test_resource.primary[0].id == "bbbb"
29+
error_message = "plan should override the value when override_during is plan"
30+
}
31+
32+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
mock_provider "test" {
2+
alias = "secondary"
3+
override_during = plan
4+
5+
mock_resource "test_resource" {
6+
defaults = {
7+
id = "ffff"
8+
}
9+
}
10+
}
11+
12+
13+
variables {
14+
instances = 2
15+
child_instances = 1
16+
}
17+
18+
run "test" {
19+
command = plan
20+
21+
assert {
22+
condition = test_resource.secondary[0].id == "ffff"
23+
error_message = "plan should use the mocked provider value when override_during is plan"
24+
}
25+
26+
}

0 commit comments

Comments
 (0)