diff --git a/internal/backend/local/backend_local.go b/internal/backend/local/backend_local.go index eb598f4c3258..dfc3bf771d9e 100644 --- a/internal/backend/local/backend_local.go +++ b/internal/backend/local/backend_local.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/configs/configload" + "github.com/hashicorp/terraform/internal/lang" "github.com/hashicorp/terraform/internal/plans/planfile" "github.com/hashicorp/terraform/internal/states/statemgr" "github.com/hashicorp/terraform/internal/terraform" @@ -516,7 +517,9 @@ var _ backend.UnparsedVariableValue = unparsedTestVariableValue{} func (v unparsedTestVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics - value, valueDiags := v.Expr.Value(nil) + value, valueDiags := v.Expr.Value(&hcl.EvalContext{ + Functions: lang.TestingFunctions(), + }) diags = diags.Append(valueDiags) if valueDiags.HasErrors() { return nil, diags diff --git a/internal/backend/local/test.go b/internal/backend/local/test.go index e56dab91098c..2739ff1d9ae2 100644 --- a/internal/backend/local/test.go +++ b/internal/backend/local/test.go @@ -1023,7 +1023,7 @@ func (runner *TestFileRunner) GetVariables(config *configs.Config, run *modulete values := make(terraform.InputValues) // First, let's look at the global variables. - for name, value := range runner.globalVariables { + for name, variable := range runner.globalVariables { if !relevantVariables[name] { // Then this run block doesn't need this value. continue @@ -1039,9 +1039,22 @@ func (runner *TestFileRunner) GetVariables(config *configs.Config, run *modulete parsingMode = cfg.ParsingMode } - var valueDiags tfdiags.Diagnostics - values[name], valueDiags = value.ParseVariableValue(parsingMode) + value, valueDiags := variable.ParseVariableValue(parsingMode) diags = diags.Append(valueDiags) + if diags.HasErrors() { + // We still add a value for this variable even though we couldn't + // parse it as we don't want to compound errors later. For example, + // the system would report this variable didn't have a value which + // would confuse the user because it does have a value, it's just + // not a valid value. We have added the diagnostics so the user + // will be informed about the error, and the test won't run. We'll + // just report only the relevant errors. + values[name] = &terraform.InputValue{ + Value: cty.NilVal, + } + continue + } + values[name] = value } // Second, we'll check the run level variables. diff --git a/internal/command/test_test.go b/internal/command/test_test.go index 4cb8192ba916..554964142a23 100644 --- a/internal/command/test_test.go +++ b/internal/command/test_test.go @@ -208,7 +208,7 @@ func TestTest_Runs(t *testing.T) { code: 0, }, "functions_available": { - expectedOut: "1 passed, 0 failed.", + expectedOut: "2 passed, 0 failed.", code: 0, }, "mocking": { @@ -227,6 +227,11 @@ func TestTest_Runs(t *testing.T) { expectedOut: "1 passed, 0 failed.", code: 0, }, + "global_var_refs": { + expectedOut: "2 failed, 1 skipped.", + expectedErr: "Variables may not be used here.", + code: 1, + }, } for name, tc := range tcs { t.Run(name, func(t *testing.T) { @@ -281,7 +286,7 @@ func TestTest_Runs(t *testing.T) { } if !strings.Contains(output.Stdout(), tc.expectedOut) { - t.Errorf("output didn't contain expected string:\n\n%s", output.All()) + t.Errorf("output didn't contain expected string:\n\n%s", output.Stdout()) } if !strings.Contains(output.Stderr(), tc.expectedErr) { diff --git a/internal/command/testdata/test/functions_available/alternate.tftest.hcl b/internal/command/testdata/test/functions_available/alternate.tftest.hcl new file mode 100644 index 000000000000..29a2f8398639 --- /dev/null +++ b/internal/command/testdata/test/functions_available/alternate.tftest.hcl @@ -0,0 +1,10 @@ +variables { + input = jsonencode({key:"value"}) +} + +run "test" { + assert { + condition = jsondecode(test_resource.resource.value).key == "value" + error_message = "wrong value" + } +} diff --git a/internal/command/testdata/test/global_var_refs/environment_variable.tftest.hcl b/internal/command/testdata/test/global_var_refs/environment_variable.tftest.hcl new file mode 100644 index 000000000000..de4195c7eb2f --- /dev/null +++ b/internal/command/testdata/test/global_var_refs/environment_variable.tftest.hcl @@ -0,0 +1,6 @@ + +variables { + input = var.env_var_input +} + +run "execute" {} diff --git a/internal/command/testdata/test/global_var_refs/main.tf b/internal/command/testdata/test/global_var_refs/main.tf new file mode 100644 index 000000000000..af996592408f --- /dev/null +++ b/internal/command/testdata/test/global_var_refs/main.tf @@ -0,0 +1,7 @@ +variable "input" { + type = string +} + +output "value" { + value = var.input +} diff --git a/internal/command/testdata/test/global_var_refs/run_block_output.tftest.hcl b/internal/command/testdata/test/global_var_refs/run_block_output.tftest.hcl new file mode 100644 index 000000000000..d3b71602af62 --- /dev/null +++ b/internal/command/testdata/test/global_var_refs/run_block_output.tftest.hcl @@ -0,0 +1,17 @@ + +variables { + input = var.setup.value +} + +run "setup" { + variables { + input = "hello" + } +} + +run "execute" { + assert { + condition = output.value == "hello" + error_message = "bad output value" + } +}