Skip to content

Commit 9896221

Browse files
refactor variable extraction
1 parent 7ae7a20 commit 9896221

File tree

1 file changed

+75
-109
lines changed

1 file changed

+75
-109
lines changed

internal/backend/local/test.go

Lines changed: 75 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -997,34 +997,30 @@ func (runner *TestFileRunner) GetVariables(config *configs.Config, run *modulete
997997
}
998998
}
999999

1000-
// Second, we'll check to see which variables the suites global variables
1001-
// themselves reference.
1002-
for _, expr := range runner.fileVariables {
1003-
for _, variable := range expr.Variables() {
1004-
reference, referenceDiags := addrs.ParseRefFromTestingScope(variable)
1005-
diags = diags.Append(referenceDiags)
1006-
if reference != nil {
1007-
if addr, ok := reference.Subject.(addrs.InputVariable); ok {
1008-
relevantVariables[addr.Name] = true
1000+
getRelevantVariables := func(src map[string]hcl.Expression) tfdiags.Diagnostics {
1001+
var getVarsDiags tfdiags.Diagnostics
1002+
for _, expr := range runner.fileVariables {
1003+
for _, variable := range expr.Variables() {
1004+
reference, referenceDiags := addrs.ParseRefFromTestingScope(variable)
1005+
getVarsDiags = getVarsDiags.Append(referenceDiags)
1006+
if reference != nil {
1007+
if addr, ok := reference.Subject.(addrs.InputVariable); ok {
1008+
relevantVariables[addr.Name] = true
1009+
}
10091010
}
10101011
}
10111012
}
1013+
return getVarsDiags
10121014
}
10131015

1016+
// Second, we'll check to see which variables the suites global variables
1017+
// themselves reference.
1018+
diags = diags.Append(getRelevantVariables(runner.fileVariables))
1019+
10141020
// Third, we'll check to see which variables the run block variables
10151021
// themselves reference. We might be processing variables just for the file
10161022
// so the run block itself could be nil.
1017-
for _, expr := range run.Config.Variables {
1018-
for _, variable := range expr.Variables() {
1019-
reference, referenceDiags := addrs.ParseRefFromTestingScope(variable)
1020-
diags = diags.Append(referenceDiags)
1021-
if reference != nil {
1022-
if addr, ok := reference.Subject.(addrs.InputVariable); ok {
1023-
relevantVariables[addr.Name] = true
1024-
}
1025-
}
1026-
}
1027-
}
1023+
diags = diags.Append(getRelevantVariables(run.Config.Variables))
10281024

10291025
// Finally, we'll check to see which variables are actually defined within
10301026
// the configuration.
@@ -1080,96 +1076,101 @@ func (runner *TestFileRunner) GetVariables(config *configs.Config, run *modulete
10801076
}
10811077

10821078
// Second, we'll check the file level variables
1083-
var exprs []hcl.Expression
1084-
for _, expr := range runner.fileVariables {
1085-
exprs = append(exprs, expr)
1079+
// This is a bit more complicated, as the file and run level variables can reference
1080+
// previously defined variables.
1081+
fileValues, fileDiags := runner.getVariablesFromConfiguration(values, relevantVariables, run.Name, runner.fileVariables)
1082+
diags = diags.Append(fileDiags)
1083+
for name, value := range fileValues {
1084+
values[name] = value
10861085
}
10871086

1088-
// Preformat the variables we've processed already - these will be made
1089-
// available to the eval context.
1090-
variables := make(map[string]cty.Value)
1091-
for name, value := range values {
1092-
variables[name] = value.Value
1087+
// Third, we'll check the run level variables.
1088+
runValues, runDiags := runner.getVariablesFromConfiguration(values, relevantVariables, run.Name, run.Config.Variables)
1089+
diags = diags.Append(runDiags)
1090+
for name, value := range runValues {
1091+
values[name] = value
10931092
}
10941093

1095-
fmt.Printf("\nvariables: \n\t%#v \n", variables)
1094+
// Finally, we check the configuration again. This is where we'll discover
1095+
// if there's any missing variables and fill in any optional variables that
1096+
// don't have a value already.
10961097

1097-
ctx, ctxDiags := hcltest.EvalContext(hcltest.TargetRunBlock, exprs, variables, runner.PriorOutputs)
1098-
diags = diags.Append(ctxDiags)
1098+
for name, variable := range config.Module.Variables {
1099+
if _, exists := values[name]; exists {
1100+
// Then we've provided a variable for this. It's all good.
1101+
continue
1102+
}
10991103

1100-
var failedContext bool
1101-
if ctxDiags.HasErrors() {
1102-
// If we couldn't build the context, we won't actually process these
1103-
// variables. Instead, we'll fill them with an empty value but still
1104-
// make a note that the user did provide them.
1105-
failedContext = true
1106-
}
1104+
// Otherwise, we're going to give these variables a value. They'll be
1105+
// processed by the Terraform graph and provided a default value later
1106+
// if they have one.
11071107

1108-
for name, expr := range runner.fileVariables {
1109-
if !relevantVariables[name] {
1110-
// We'll add a warning for this. Since we're right in the run block
1111-
// users shouldn't be defining variables that are not relevant.
1108+
if variable.Required() {
11121109
diags = diags.Append(&hcl.Diagnostic{
1113-
Severity: hcl.DiagWarning,
1114-
Summary: "Value for undeclared variable",
1115-
Detail: fmt.Sprintf("The module under test does not declare a variable named %q, but it is declared in run block %q.", name, run.Name),
1116-
Subject: expr.Range().Ptr(),
1110+
Severity: hcl.DiagError,
1111+
Summary: "No value for required variable",
1112+
Detail: fmt.Sprintf("The module under test for run block %q has a required variable %q with no set value. Use a -var or -var-file command line argument or add this variable into a \"variables\" block within the test file or run block.",
1113+
run.Name, variable.Name),
1114+
Subject: variable.DeclRange.Ptr(),
11171115
})
1118-
continue
1119-
}
11201116

1121-
value := cty.NilVal
1122-
if !failedContext {
1123-
var valueDiags hcl.Diagnostics
1124-
value, valueDiags = expr.Value(ctx)
1125-
diags = diags.Append(valueDiags)
1117+
values[name] = &terraform.InputValue{
1118+
Value: cty.DynamicVal,
1119+
SourceType: terraform.ValueFromConfig,
1120+
SourceRange: tfdiags.SourceRangeFromHCL(variable.DeclRange),
1121+
}
1122+
} else {
1123+
values[name] = &terraform.InputValue{
1124+
Value: cty.NilVal,
1125+
SourceType: terraform.ValueFromConfig,
1126+
SourceRange: tfdiags.SourceRangeFromHCL(variable.DeclRange),
1127+
}
11261128
}
11271129

1128-
values[name] = &terraform.InputValue{
1129-
Value: value,
1130-
SourceType: terraform.ValueFromConfig,
1131-
SourceRange: tfdiags.SourceRangeFromHCL(expr.Range()),
1132-
}
11331130
}
11341131

1135-
// Third, we'll check the run level variables.
1132+
return values, diags
1133+
}
11361134

1137-
// This is a bit more complicated, as the run level variables can reference
1138-
// previously defined variables.
1135+
// getVariablesFromConfiguration will process the variables from the configuration
1136+
// and return a map of the variables and their values.
1137+
func (runner *TestFileRunner) getVariablesFromConfiguration(knownVariables terraform.InputValues, relevantVariables map[string]bool, runName string, variableConfig map[string]hcl.Expression) (terraform.InputValues, tfdiags.Diagnostics) {
1138+
var exprs []hcl.Expression
1139+
var diags tfdiags.Diagnostics
1140+
variableValues := make(terraform.InputValues)
11391141

11401142
// Preload the available expressions, we're going to validate them when we
11411143
// build the context.
1142-
exprs = []hcl.Expression{}
1143-
for _, expr := range run.Config.Variables {
1144+
for _, expr := range runner.fileVariables {
11441145
exprs = append(exprs, expr)
11451146
}
11461147

11471148
// Preformat the variables we've processed already - these will be made
11481149
// available to the eval context.
1149-
variables = make(map[string]cty.Value)
1150-
for name, value := range values {
1150+
variables := make(map[string]cty.Value)
1151+
for name, value := range knownVariables {
11511152
variables[name] = value.Value
11521153
}
11531154

1154-
ctx, ctxDiags = hcltest.EvalContext(hcltest.TargetRunBlock, exprs, variables, runner.PriorOutputs)
1155+
ctx, ctxDiags := hcltest.EvalContext(hcltest.TargetRunBlock, exprs, variables, runner.PriorOutputs)
11551156
diags = diags.Append(ctxDiags)
11561157

1157-
failedContext = false
1158+
var failedContext bool
11581159
if ctxDiags.HasErrors() {
11591160
// If we couldn't build the context, we won't actually process these
11601161
// variables. Instead, we'll fill them with an empty value but still
11611162
// make a note that the user did provide them.
11621163
failedContext = true
11631164
}
11641165

1165-
for name, expr := range run.Config.Variables {
1166+
for name, expr := range runner.fileVariables {
11661167
if !relevantVariables[name] {
11671168
// We'll add a warning for this. Since we're right in the run block
11681169
// users shouldn't be defining variables that are not relevant.
11691170
diags = diags.Append(&hcl.Diagnostic{
11701171
Severity: hcl.DiagWarning,
11711172
Summary: "Value for undeclared variable",
1172-
Detail: fmt.Sprintf("The module under test does not declare a variable named %q, but it is declared in run block %q.", name, run.Name),
1173+
Detail: fmt.Sprintf("The module under test does not declare a variable named %q, but it is declared in run block %q.", name, runName),
11731174
Subject: expr.Range().Ptr(),
11741175
})
11751176
continue
@@ -1182,52 +1183,14 @@ func (runner *TestFileRunner) GetVariables(config *configs.Config, run *modulete
11821183
diags = diags.Append(valueDiags)
11831184
}
11841185

1185-
values[name] = &terraform.InputValue{
1186+
variableValues[name] = &terraform.InputValue{
11861187
Value: value,
11871188
SourceType: terraform.ValueFromConfig,
11881189
SourceRange: tfdiags.SourceRangeFromHCL(expr.Range()),
11891190
}
11901191
}
11911192

1192-
// Finally, we check the configuration again. This is where we'll discover
1193-
// if there's any missing variables and fill in any optional variables that
1194-
// don't have a value already.
1195-
1196-
for name, variable := range config.Module.Variables {
1197-
if _, exists := values[name]; exists {
1198-
// Then we've provided a variable for this. It's all good.
1199-
continue
1200-
}
1201-
1202-
// Otherwise, we're going to give these variables a value. They'll be
1203-
// processed by the Terraform graph and provided a default value later
1204-
// if they have one.
1205-
1206-
if variable.Required() {
1207-
diags = diags.Append(&hcl.Diagnostic{
1208-
Severity: hcl.DiagError,
1209-
Summary: "No value for required variable",
1210-
Detail: fmt.Sprintf("The module under test for run block %q has a required variable %q with no set value. Use a -var or -var-file command line argument or add this variable into a \"variables\" block within the test file or run block.",
1211-
run.Name, variable.Name),
1212-
Subject: variable.DeclRange.Ptr(),
1213-
})
1214-
1215-
values[name] = &terraform.InputValue{
1216-
Value: cty.DynamicVal,
1217-
SourceType: terraform.ValueFromConfig,
1218-
SourceRange: tfdiags.SourceRangeFromHCL(variable.DeclRange),
1219-
}
1220-
} else {
1221-
values[name] = &terraform.InputValue{
1222-
Value: cty.NilVal,
1223-
SourceType: terraform.ValueFromConfig,
1224-
SourceRange: tfdiags.SourceRangeFromHCL(variable.DeclRange),
1225-
}
1226-
}
1227-
1228-
}
1229-
1230-
return values, diags
1193+
return variableValues, diags
12311194
}
12321195

12331196
// FilterVariablesToModule splits the provided values into two disjoint maps:
@@ -1324,17 +1287,20 @@ func (runner *TestFileRunner) AddVariablesToConfig(config *configs.Config, varia
13241287
// the file.
13251288
func (runner *TestFileRunner) initVariables(file *moduletest.File) {
13261289
runner.globalVariables = make(map[string]backend.UnparsedVariableValue)
1290+
fmt.Printf("\nrunner.Suite.GlobalVariables: \n\t%#v \n", runner.Suite.GlobalVariables)
13271291
for name, value := range runner.Suite.GlobalVariables {
13281292
runner.globalVariables[name] = value
13291293
}
13301294
if filepath.Dir(file.Name) == runner.Suite.TestingDirectory {
13311295
// If the file is in the testing directory, then also include any
13321296
// variables that are defined within the default variable file also in
13331297
// the test directory.
1298+
fmt.Printf("\nrunner.Suite.GlobalTestVariables: \n\t%#v \n", runner.Suite.GlobalTestVariables)
13341299
for name, value := range runner.Suite.GlobalTestVariables {
13351300
runner.globalVariables[name] = value
13361301
}
13371302
}
1303+
fmt.Printf("\nfile.Config.Variables: \n\t%#v \n", file.Config.Variables)
13381304
runner.fileVariables = make(map[string]hcl.Expression)
13391305
for name, expr := range file.Config.Variables {
13401306
runner.fileVariables[name] = expr

0 commit comments

Comments
 (0)