mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
test framework: expand variables available to test assertions (#33611)
This commit is contained in:
parent
bf6f32c19a
commit
3bea1171af
@ -9,6 +9,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/internal/backend"
|
||||
"github.com/hashicorp/terraform/internal/command/arguments"
|
||||
@ -507,7 +509,9 @@ func (runner *TestRunner) ExecuteTestRun(mgr *TestStateManager, run *moduletest.
|
||||
run.Diagnostics = run.Diagnostics.Append(diags)
|
||||
}
|
||||
|
||||
variables, diags := buildInputVariablesForAssertions(run, file, globals)
|
||||
variables, reset, diags := prepareInputVariablesForAssertions(config, run, file, globals)
|
||||
defer reset()
|
||||
|
||||
run.Diagnostics = run.Diagnostics.Append(diags)
|
||||
if diags.HasErrors() {
|
||||
run.Status = moduletest.Error
|
||||
@ -943,7 +947,7 @@ func (manager *TestStateManager) cleanupStates(file *moduletest.File, globals ma
|
||||
// buildInputVariablesForTest creates a terraform.InputValues mapping for
|
||||
// variable values that are relevant to the config being tested.
|
||||
//
|
||||
// Crucially, it differs from buildInputVariablesForAssertions in that it only
|
||||
// Crucially, it differs from prepareInputVariablesForAssertions in that it only
|
||||
// includes variables that are reference by the config and not everything that
|
||||
// is defined within the test run block and test file.
|
||||
func buildInputVariablesForTest(run *moduletest.Run, file *moduletest.File, config *configs.Config, globals map[string]backend.UnparsedVariableValue) (terraform.InputValues, tfdiags.Diagnostics) {
|
||||
@ -986,15 +990,19 @@ func buildInputVariablesForTest(run *moduletest.Run, file *moduletest.File, conf
|
||||
return backend.ParseVariableValues(variables, config.Module.Variables)
|
||||
}
|
||||
|
||||
// buildInputVariablesForAssertions creates a terraform.InputValues mapping that
|
||||
// contains all the variables defined for a given run and file, alongside any
|
||||
// unset variables that have defaults within the provided config.
|
||||
// prepareInputVariablesForAssertions creates a terraform.InputValues mapping
|
||||
// that contains all the variables defined for a given run and file, alongside
|
||||
// any unset variables that have defaults within the provided config.
|
||||
//
|
||||
// Crucially, it differs from buildInputVariablesForTest in that the returned
|
||||
// input values include all variables available even if they are not defined
|
||||
// within the config. This allows the assertions to refer to variables defined
|
||||
// solely within the test file, and not only those within the configuration.
|
||||
func buildInputVariablesForAssertions(run *moduletest.Run, file *moduletest.File, globals map[string]backend.UnparsedVariableValue) (terraform.InputValues, tfdiags.Diagnostics) {
|
||||
//
|
||||
// In addition, it modifies the provided config so that any variables that are
|
||||
// available are also defined in the config. It returns a function that resets
|
||||
// the config which must be called so the config can be reused going forward.
|
||||
func prepareInputVariablesForAssertions(config *configs.Config, run *moduletest.Run, file *moduletest.File, globals map[string]backend.UnparsedVariableValue) (terraform.InputValues, func(), tfdiags.Diagnostics) {
|
||||
variables := make(map[string]backend.UnparsedVariableValue)
|
||||
|
||||
if run != nil {
|
||||
@ -1030,6 +1038,9 @@ func buildInputVariablesForAssertions(run *moduletest.Run, file *moduletest.File
|
||||
variables[name] = variable
|
||||
}
|
||||
|
||||
// We've gathered all the values we have, let's convert them into
|
||||
// terraform.InputValues so they can be passed into the Terraform graph.
|
||||
|
||||
inputs := make(terraform.InputValues, len(variables))
|
||||
var diags tfdiags.Diagnostics
|
||||
for name, variable := range variables {
|
||||
@ -1037,5 +1048,59 @@ func buildInputVariablesForAssertions(run *moduletest.Run, file *moduletest.File
|
||||
diags = diags.Append(valueDiags)
|
||||
inputs[name] = value
|
||||
}
|
||||
return inputs, diags
|
||||
|
||||
// Next, we're going to apply any default values from the configuration.
|
||||
// We do this after the conversion into terraform.InputValues, as the
|
||||
// defaults have already been converted into cty.Value objects.
|
||||
|
||||
for name, variable := range config.Module.Variables {
|
||||
if _, exists := variables[name]; exists {
|
||||
// Then we don't want to apply the default for this variable as we
|
||||
// already have a value.
|
||||
continue
|
||||
}
|
||||
|
||||
if variable.Default != cty.NilVal {
|
||||
inputs[name] = &terraform.InputValue{
|
||||
Value: variable.Default,
|
||||
SourceType: terraform.ValueFromConfig,
|
||||
SourceRange: tfdiags.SourceRangeFromHCL(variable.DeclRange),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, we're going to do a some modifications to the config.
|
||||
// If we have got variable values from the test file we need to make sure
|
||||
// they have an equivalent entry in the configuration. We're going to do
|
||||
// that dynamically here.
|
||||
|
||||
// First, take a backup of the existing configuration so we can easily
|
||||
// restore it later.
|
||||
currentVars := make(map[string]*configs.Variable)
|
||||
for name, variable := range config.Module.Variables {
|
||||
currentVars[name] = variable
|
||||
}
|
||||
|
||||
// Next, let's go through our entire inputs and add any that aren't already
|
||||
// defined into the config.
|
||||
for name, value := range inputs {
|
||||
if _, exists := config.Module.Variables[name]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
config.Module.Variables[name] = &configs.Variable{
|
||||
Name: name,
|
||||
Type: value.Value.Type(),
|
||||
ConstraintType: value.Value.Type(),
|
||||
DeclRange: value.SourceRange.ToHCL(),
|
||||
}
|
||||
}
|
||||
|
||||
// We return our input values, a function that will reset the variables
|
||||
// within the config so it can be used again, and any diagnostics reporting
|
||||
// variables that we couldn't parse.
|
||||
|
||||
return inputs, func() {
|
||||
config.Module.Variables = currentVars
|
||||
}, diags
|
||||
}
|
||||
|
@ -124,6 +124,14 @@ func TestTest(t *testing.T) {
|
||||
expected: "1 passed, 0 failed",
|
||||
code: 0,
|
||||
},
|
||||
"default_variables": {
|
||||
expected: "1 passed, 0 failed.",
|
||||
code: 0,
|
||||
},
|
||||
"undefined_variables": {
|
||||
expected: "1 passed, 0 failed.",
|
||||
code: 0,
|
||||
},
|
||||
}
|
||||
for name, tc := range tcs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
|
5
internal/command/testdata/test/default_variables/main.tf
vendored
Normal file
5
internal/command/testdata/test/default_variables/main.tf
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
variable "input" {
|
||||
type = string
|
||||
default = "Hello, world!"
|
||||
}
|
7
internal/command/testdata/test/default_variables/main.tftest.hcl
vendored
Normal file
7
internal/command/testdata/test/default_variables/main.tftest.hcl
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
run "applies_defaults" {
|
||||
assert {
|
||||
condition = var.input == "Hello, world!"
|
||||
error_message = "should have applied default value"
|
||||
}
|
||||
}
|
5
internal/command/testdata/test/undefined_variables/main.tf
vendored
Normal file
5
internal/command/testdata/test/undefined_variables/main.tf
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
variable "input" {
|
||||
type = string
|
||||
default = "Hello, world!"
|
||||
}
|
13
internal/command/testdata/test/undefined_variables/main.tftest.hcl
vendored
Normal file
13
internal/command/testdata/test/undefined_variables/main.tftest.hcl
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
variables {
|
||||
# config_free isn't defined in the config, but we'll
|
||||
# still let users refer to it within the assertions.
|
||||
config_free = "Hello, world!"
|
||||
}
|
||||
|
||||
run "applies_defaults" {
|
||||
assert {
|
||||
condition = var.input == var.config_free
|
||||
error_message = "should have applied default value"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user