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: Collect variables from default var file within testing directory #34341

Merged
merged 9 commits into from
Dec 4, 2023
18 changes: 16 additions & 2 deletions internal/backend/local/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@ const (
type TestSuiteRunner struct {
Config *configs.Config

GlobalVariables map[string]backend.UnparsedVariableValue
Opts *terraform.ContextOpts
TestingDirectory string

// Global variables comes from the main configuration directory,
// and the Global Test Variables are loaded from the test directory.
GlobalVariables map[string]backend.UnparsedVariableValue
GlobalTestVariables map[string]backend.UnparsedVariableValue

Opts *terraform.ContextOpts

View views.Test

Expand Down Expand Up @@ -1216,6 +1222,14 @@ func (runner *TestFileRunner) initVariables(file *moduletest.File) {
for name, value := range runner.Suite.GlobalVariables {
runner.globalVariables[name] = value
}
if path.Dir(file.Name) == runner.Suite.TestingDirectory {
// If the file is in the testing directory, then also include any
// variables that are defined within the default variable file also in
// the test directory.
for name, value := range runner.Suite.GlobalTestVariables {
runner.globalVariables[name] = value
}
}
Comment on lines +1225 to +1232
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JKIPIKA, I resolved the diffs by undoing your changes to the other function and adding the relevant change directly in here instead.

You didn't do anything wrong, this function isn't available within the v1.6 branch so you did the right thing in your original PR. It's just we will have introduced this function at some point after the v1.6 launch for managing the global variables and it's much easier to add here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I get it now, thanks for explanation!

for name, expr := range file.Config.Variables {
runner.globalVariables[name] = unparsedTestVariableValue{expr}
}
Expand Down
46 changes: 46 additions & 0 deletions internal/command/meta_vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"

"github.com/hashicorp/hcl/v2"
Expand All @@ -23,6 +24,51 @@ import (
// for root module input variables.
const VarEnvPrefix = "TF_VAR_"

// collectVariableValuesForTests inspects the various places that test
// values can come from and constructs a map ready to be passed to the
// backend as part of a backend.Operation.
//
// This method returns diagnostics relating to the collection of the values,
// but the values themselves may produce additional diagnostics when finally
// parsed.
func (m *Meta) collectVariableValuesForTests(testsFilePath string) (map[string]backend.UnparsedVariableValue, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
ret := map[string]backend.UnparsedVariableValue{}

// We collect the variables from the ./tests directory
// there is no other need to process environmental variables
// as this is done via collectVariableValues function
if testsFilePath == "" {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Warning,
"Missing test directory",
"The test directory was unspecified when it should always be set. This is a bug in Terraform - please report it."))
return ret, diags
}

// Firstly we collect variables from .tfvars file
testVarsFilename := filepath.Join(testsFilePath, DefaultVarsFilename)
if _, err := os.Stat(testVarsFilename); err == nil {
moreDiags := m.addVarsFromFile(testVarsFilename, terraform.ValueFromAutoFile, ret)
diags = diags.Append(moreDiags)

}

// Then we collect variables from .tfvars.json file
const defaultVarsFilenameJSON = DefaultVarsFilename + ".json"
testVarsFilenameJSON := filepath.Join(testsFilePath, defaultVarsFilenameJSON)

if _, err := os.Stat(testVarsFilenameJSON); err == nil {
moreDiags := m.addVarsFromFile(testVarsFilenameJSON, terraform.ValueFromAutoFile, ret)
diags = diags.Append(moreDiags)
}

// Also, no need to additionally process variables from command line,
// as this is also done via collectVariableValues

return ret, diags
}

// collectVariableValues inspects the various places that root module input variable
// values can come from and constructs a map ready to be passed to the
// backend as part of a backend.Operation.
Expand Down
30 changes: 20 additions & 10 deletions internal/command/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ func (c *TestCommand) Run(rawArgs []string) int {
}
c.variableArgs = rawFlags{items: &items}

// Collect variables for "terraform test"
testVariables, variableDiags := c.collectVariableValuesForTests(args.TestDirectory)
diags = diags.Append(variableDiags)

variables, variableDiags := c.collectVariableValues()
diags = diags.Append(variableDiags)
if variableDiags.HasErrors() {
Expand Down Expand Up @@ -195,16 +199,22 @@ func (c *TestCommand) Run(rawArgs []string) int {
}
} else {
runner = &local.TestSuiteRunner{
Config: config,
GlobalVariables: variables,
Opts: opts,
View: view,
Stopped: false,
Cancelled: false,
StoppedCtx: stopCtx,
CancelledCtx: cancelCtx,
Filter: args.Filter,
Verbose: args.Verbose,
Config: config,
// The GlobalVariables are loaded from the
// main configuration directory
// The GlobalTestVariables are loaded from the
// test directory
GlobalVariables: variables,
GlobalTestVariables: testVariables,
TestingDirectory: args.TestDirectory,
Opts: opts,
View: view,
Stopped: false,
Cancelled: false,
StoppedCtx: stopCtx,
CancelledCtx: cancelCtx,
Filter: args.Filter,
Verbose: args.Verbose,
}
}

Expand Down
4 changes: 4 additions & 0 deletions internal/command/test_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ func TestTest(t *testing.T) {
expectedOut: "4 passed, 0 failed.",
code: 0,
},
"tfvars_in_test_dir": {
expectedOut: "2 passed, 0 failed.",
code: 0,
},
"functions_available": {
expectedOut: "1 passed, 0 failed.",
code: 0,
Expand Down
17 changes: 17 additions & 0 deletions internal/command/testdata/test/tfvars_in_test_dir/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
variable "foo" {
description = "This is test variable"
default = "def_value"
}

variable "fooJSON" {
description = "This is test variable"
default = "def_value"
}

output "out_foo" {
value = var.foo
}

output "out_fooJSON" {
value = var.fooJSON
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
run "primary" {
assert {
condition = var.foo == var.test_foo
error_message = "Expected: ${var.test_foo}, Actual: ${var.foo}"
}
}

run "secondary" {
assert {
condition = var.fooJSON == var.test_foo_json
error_message = "Expected: ${var.test_foo_json}, Actual: ${var.fooJSON}"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
foo = "foo_tfvars_value"
test_foo = "foo_tfvars_value"
test_foo_json = "foo_json_tfvars_value"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"fooJSON": "foo_json_tfvars_value"
}