Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

terraform test: allow computed/mocked values override during planning #36227

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
24 changes: 19 additions & 5 deletions internal/command/test_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,25 @@ func TestTest_Runs(t *testing.T) {
code: 0,
},
"mocking": {
expectedOut: []string{"6 passed, 0 failed."},
expectedOut: []string{"9 passed, 0 failed."},
code: 0,
},
"mocking-invalid": {
expectedErr: []string{"Invalid outputs attribute"},
initCode: 1,
expectedErr: []string{
"Invalid outputs attribute",
"The override_computed attribute must be a boolean.",
},
initCode: 1,
},
"mocking-error": {
expectedErr: []string{
"Unknown condition value",
"plan_mocked_overridden.tftest.hcl",
"test_resource.primary[0].id",
"plan_mocked_provider.tftest.hcl",
"test_resource.secondary[0].id",
},
code: 1,
},
"dangling_data_block": {
expectedOut: []string{"2 passed, 0 failed."},
Expand Down Expand Up @@ -1748,8 +1761,9 @@ Condition expression could not be evaluated at this time. This means you have
executed a %s block with %s and one of the values your
condition depended on is not known until after the plan has been applied.
Either remove this value from your condition, or execute an %s command
from this %s block.
`, "`run`", "`command = plan`", "`apply`", "`run`"),
from this %s block. Alternatively, if there is an override for this value,
you can make it available during the plan phase by setting %s in the %s block.
`, "`run`", "`command = plan`", "`apply`", "`run`", "`override_computed\n= true`", "`override_`"),
},
"unknown_value_in_vars": {
code: 1,
Expand Down
30 changes: 30 additions & 0 deletions internal/command/testdata/test/mocking-error/child/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
terraform {
required_providers {
test = {
source = "hashicorp/test"
configuration_aliases = [test.primary, test.secondary]
}
}
}

variable "instances" {
type = number
}

resource "test_resource" "primary" {
provider = test.primary
count = var.instances
}

resource "test_resource" "secondary" {
provider = test.secondary
count = var.instances
}

output "primary" {
value = test_resource.primary
}

output "secondary" {
value = test_resource.secondary
}
46 changes: 46 additions & 0 deletions internal/command/testdata/test/mocking-error/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
terraform {
required_providers {
test = {
source = "hashicorp/test"
}
}
}

provider "test" {
alias = "primary"
}

provider "test" {
alias = "secondary"
}

variable "instances" {
type = number
}

variable "child_instances" {
type = number
}

resource "test_resource" "primary" {
provider = test.primary
count = var.instances
}

resource "test_resource" "secondary" {
provider = test.secondary
count = var.instances
}

module "child" {
count = var.instances

source = "./child"

providers = {
test.primary = test.primary
test.secondary = test.secondary
}

instances = var.child_instances
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
mock_provider "test" {
alias = "primary"

mock_resource "test_resource" {
defaults = {
id = "aaaa"
}
}

override_resource {
target = test_resource.primary
values = {
id = "bbbb"
}
}
}

variables {
instances = 1
child_instances = 1
}

// This test will fail because the plan command does not use the
// overridden values for computed properties,
// making the left-hand side of the condition unknown.
run "test" {
command = plan

assert {
condition = test_resource.primary[0].id == "bbbb"
error_message = "plan should not have the overridden value"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
mock_provider "test" {
alias = "secondary"

mock_resource "test_resource" {
defaults = {
id = "ffff"
}
}
}


variables {
instances = 2
child_instances = 1
}

run "test" {
command = plan

assert {
condition = test_resource.secondary[0].id == "ffff"
error_message = "plan should use the mocked provider value when override_computed is true"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
mock_provider "test" {
alias = "primary"
override_computed = foo // This should be a boolean value, therefore this test should fail

mock_resource "test_resource" {
defaults = {
id = "aaaa"
}
}

override_resource {
target = test_resource.primary
values = {
id = "bbbb"
}
}
}

variables {
instances = 1
child_instances = 1
}

run "test" {

assert {
condition = test_resource.primary[0].id == "bbbb"
error_message = "mock not applied"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
mock_provider "test" {
alias = "primary"

mock_resource "test_resource" {
defaults = {
id = "aaaa"
}
}

override_resource {
target = test_resource.primary
override_computed = true
values = {
id = "bbbb"
}
}
}

variables {
instances = 1
child_instances = 1
}

run "test" {
command = plan

assert {
condition = test_resource.primary[0].id == "bbbb"
error_message = "plan should override the value when override_computed is true"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
mock_provider "test" {
alias = "secondary"
override_computed = true

mock_resource "test_resource" {
defaults = {
id = "ffff"
}
}
}


variables {
instances = 2
child_instances = 1
}

run "test" {
command = plan

assert {
condition = test_resource.secondary[0].id == "ffff"
error_message = "plan should use the mocked provider value when override_computed is true"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
mock_provider "test" {
alias = "primary"
override_computed = true

mock_resource "test_resource" {
defaults = {
id = "aaaa"
}
}

override_resource {
target = test_resource.primary
values = {
id = "bbbb"
}
}

override_resource {
target = test_resource.primary[1]
override_computed = false // this should take precedence over the provider-level override_computed
values = {
id = "bbbb"
}
}
}


override_resource {
target = test_resource.secondary[0]
override_computed = true
values = {
id = "ssss"
}
}


variables {
instances = 2
child_instances = 1
}

run "test" {
command = plan

assert {
condition = test_resource.primary[0].id == "bbbb"
error_message = "plan should override the value when override_computed is true"
}

assert {
condition = test_resource.secondary[0].id == "ssss"
error_message = "plan should override the value when override_computed is true"
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,16 @@ run "test" {
error_message = "did not apply mocks"
}

assert {
// Override should not affect the other instances
condition = !contains(["aaaa", "cccc"], test_resource.secondary[0].id)
error_message = "override from another instance affected this instance"
}

assert {
// Provider Override should propagate to the child module
condition = module.child[0].primary[0].id == "aaaa"
error_message = "did not apply mocks"
}

}
Loading
Loading