diff --git a/config/variable.go b/config/variable.go new file mode 100644 index 000000000..8928685fe --- /dev/null +++ b/config/variable.go @@ -0,0 +1,175 @@ +package config + +import ( + "bytes" + "encoding/json" + "fmt" + "math/big" + "os" + "path/filepath" + + "golang.org/x/exp/constraints" +) + +const autoTFVarsJson = "generated.auto.tfvars.json" + +type Variables map[string]Variable + +func (v Variables) Write(dest string) error { + buf := bytes.NewBuffer(nil) + + buf.Write([]byte(`{`)) + + for k, val := range v { + j, err := val.MarshalJSON() + + if err != nil { + return err + } + + buf.Write([]byte(fmt.Sprintf("%q: ", k))) + buf.Write(j) + buf.Write([]byte(",")) + } + + b := bytes.TrimRight(buf.Bytes(), ",") + + buf = bytes.NewBuffer(b) + + buf.Write([]byte(`}`)) + + outFilename := filepath.Join(dest, autoTFVarsJson) + + err := os.WriteFile(outFilename, buf.Bytes(), 0700) + + if err != nil { + return err + } + + return nil +} + +type Variable interface { + json.Marshaler +} + +func BoolVariable(value bool) boolVariable { + return boolVariable{ + value: value, + } +} + +type boolVariable struct { + value bool +} + +func (t boolVariable) MarshalJSON() ([]byte, error) { + return json.Marshal(t.value) +} + +func ListVariable(value ...Variable) listVariable { + return listVariable{ + value: value, + } +} + +type listVariable struct { + value []Variable +} + +func (t listVariable) MarshalJSON() ([]byte, error) { + return json.Marshal(t.value) +} + +func MapVariable(value map[string]Variable) mapVariable { + return mapVariable{ + value: value, + } +} + +type mapVariable struct { + value map[string]Variable +} + +func (t mapVariable) MarshalJSON() ([]byte, error) { + return json.Marshal(t.value) +} + +func ObjectVariable(value map[string]Variable) objectVariable { + return objectVariable{ + value: value, + } +} + +type objectVariable struct { + value map[string]Variable +} + +func (t objectVariable) MarshalJSON() ([]byte, error) { + return json.Marshal(t.value) +} + +type number interface { + constraints.Float | constraints.Integer | *big.Float +} + +func NumberVariable[T number](value T) numberVariable { + return numberVariable{ + value: value, + } +} + +type numberVariable struct { + value any +} + +func (t numberVariable) MarshalJSON() ([]byte, error) { + switch v := t.value.(type) { + case *big.Float: + return []byte(v.Text('g', -1)), nil + } + + return json.Marshal(t.value) +} + +func SetVariable(value ...Variable) setVariable { + return setVariable{ + value: value, + } +} + +type setVariable struct { + value []Variable +} + +func (t setVariable) MarshalJSON() ([]byte, error) { + return json.Marshal(t.value) +} + +func StringVariable(value string) stringVariable { + return stringVariable{ + value: value, + } +} + +type stringVariable struct { + value string +} + +func (t stringVariable) MarshalJSON() ([]byte, error) { + return json.Marshal(t.value) +} + +func TupleVariable(value ...Variable) tupleVariable { + return tupleVariable{ + value: value, + } +} + +type tupleVariable struct { + value []Variable +} + +func (t tupleVariable) MarshalJSON() ([]byte, error) { + return json.Marshal(t.value) +} diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/provider.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/provider.tf new file mode 100644 index 000000000..4e7b51e38 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/provider.tf @@ -0,0 +1,4 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "random" {} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/random.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/random.tf new file mode 100644 index 000000000..3a652203f --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/random.tf @@ -0,0 +1,8 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/terraform.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/terraform.tf new file mode 100644 index 000000000..52f5ef4ad --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/terraform.tf @@ -0,0 +1,11 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.2.0" + } + } +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/vars.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_Vars/random.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_Vars/random.tf new file mode 100644 index 000000000..4aa0668d9 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_Vars/random.tf @@ -0,0 +1,19 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.2.0" + } + } +} + +provider "random" {} + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_Vars/vars.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_Vars/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_Vars/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars/provider.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars/provider.tf new file mode 100644 index 000000000..4e7b51e38 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars/provider.tf @@ -0,0 +1,4 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "random" {} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars/random.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars/random.tf new file mode 100644 index 000000000..6ca8f0bb1 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars/random.tf @@ -0,0 +1,8 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "random_password" "test" { + length = 8 + + numeric = false +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars/terraform.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars/terraform.tf new file mode 100644 index 000000000..1aaa98022 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars/terraform.tf @@ -0,0 +1,11 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.5.1" + } + } +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_Vars/random.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_Vars/random.tf new file mode 100644 index 000000000..66518ceeb --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_Vars/random.tf @@ -0,0 +1,19 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.5.1" + } + } +} + +provider "random" {} + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_Vars/vars.tf b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_Vars/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestNameDirectory_Vars/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/provider.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/provider.tf new file mode 100644 index 000000000..4e7b51e38 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/provider.tf @@ -0,0 +1,4 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "random" {} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/random.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/random.tf new file mode 100644 index 000000000..3a652203f --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/random.tf @@ -0,0 +1,8 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/terraform.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/terraform.tf new file mode 100644 index 000000000..52f5ef4ad --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/terraform.tf @@ -0,0 +1,11 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.2.0" + } + } +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/vars.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars/1/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_Vars/1/random.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_Vars/1/random.tf new file mode 100644 index 000000000..4aa0668d9 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_Vars/1/random.tf @@ -0,0 +1,19 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.2.0" + } + } +} + +provider "random" {} + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_Vars/1/vars.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_Vars/1/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_Vars/1/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/provider.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/provider.tf new file mode 100644 index 000000000..4e7b51e38 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/provider.tf @@ -0,0 +1,4 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "random" {} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/random.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/random.tf new file mode 100644 index 000000000..3a652203f --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/random.tf @@ -0,0 +1,8 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/terraform.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/terraform.tf new file mode 100644 index 000000000..1aaa98022 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/terraform.tf @@ -0,0 +1,11 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.5.1" + } + } +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/vars.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars/1/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_Vars/1/random.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_Vars/1/random.tf new file mode 100644 index 000000000..66518ceeb --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_Vars/1/random.tf @@ -0,0 +1,19 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.5.1" + } + } +} + +provider "random" {} + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_Vars/1/vars.tf b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_Vars/1/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/TestTest_ConfigDirectory_TestStepDirectory_Vars/1/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/config_directory_test.go b/config_directory_test/config_directory_test.go index b6e07bab2..5097916d4 100644 --- a/config_directory_test/config_directory_test.go +++ b/config_directory_test/config_directory_test.go @@ -29,6 +29,36 @@ func TestTest_ConfigDirectory_StaticDirectory(t *testing.T) { }) } +func TestTest_ConfigDirectory_StaticDirectory_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory(`fixtures/random_password_3.5.1_vars`), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + Check: resource.TestCheckResourceAttrSet("random_password.test", "id"), + }, + }, + }) +} + +func TestTest_ConfigDirectory_StaticDirectory_VarsMissing(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory(`fixtures/random_password_3.5.1_vars`), + Check: resource.TestCheckResourceAttrSet("random_password.test", "id"), + ExpectError: regexp.MustCompile(`.*Error: No value for required variable`)}, + }, + }) +} + func TestTest_ConfigDirectory_TestNameDirectory(t *testing.T) { t.Parallel() @@ -42,6 +72,23 @@ func TestTest_ConfigDirectory_TestNameDirectory(t *testing.T) { }) } +func TestTest_ConfigDirectory_TestNameDirectory_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestNameDirectory(t), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + Check: resource.TestCheckResourceAttrSet("random_password.test", "id"), + }, + }, + }) +} + func TestTest_ConfigDirectory_TestStepDirectory(t *testing.T) { t.Parallel() @@ -55,6 +102,23 @@ func TestTest_ConfigDirectory_TestStepDirectory(t *testing.T) { }) } +func TestTest_ConfigDirectory_TestStepDirectory_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestStepDirectory(t), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + Check: resource.TestCheckResourceAttrSet("random_password.test", "id"), + }, + }, + }) +} + func TestTest_ConfigDirectory_StaticDirectory_MultipleFiles(t *testing.T) { t.Parallel() @@ -68,6 +132,23 @@ func TestTest_ConfigDirectory_StaticDirectory_MultipleFiles(t *testing.T) { }) } +func TestTest_ConfigDirectory_StaticDirectory_MultipleFiles_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory(`fixtures/random_password_3.5.1_multiple_files_vars`), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + Check: resource.TestCheckResourceAttrSet("random_password.test", "id"), + }, + }, + }) +} + func TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles(t *testing.T) { t.Parallel() @@ -81,6 +162,23 @@ func TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles(t *testing.T) { }) } +func TestTest_ConfigDirectory_TestNameDirectory_MultipleFiles_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestNameDirectory(t), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + Check: resource.TestCheckResourceAttrSet("random_password.test", "id"), + }, + }, + }) +} + func TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles(t *testing.T) { t.Parallel() @@ -94,6 +192,23 @@ func TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles(t *testing.T) { }) } +func TestTest_ConfigDirectory_TestStepDirectory_MultipleFiles_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestStepDirectory(t), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + Check: resource.TestCheckResourceAttrSet("random_password.test", "id"), + }, + }, + }) +} + // TestTest_ConfigDirectory_StaticDirectory_AttributeDoesNotExist uses Terraform // configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the // random provider password resource. This test confirms that the TestCase ExternalProviders @@ -111,6 +226,27 @@ func TestTest_ConfigDirectory_StaticDirectory_AttributeDoesNotExist(t *testing.T }) } +// TestTest_ConfigDirectory_StaticDirectory_AttributeDoesNotExist_Vars uses Terraform +// configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the +// random provider password resource. This test confirms that the TestCase ExternalProviders +// is being used when ConfigDirectory is set. +func TestTest_ConfigDirectory_StaticDirectory_AttributeDoesNotExist_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory(`fixtures/random_password_3.2.0_vars`), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + ExpectError: regexp.MustCompile(`.*An argument named "numeric" is not expected here.`), + }, + }, + }) +} + // TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist uses Terraform // configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the // random provider password resource. This test confirms that the TestCase ExternalProviders @@ -128,6 +264,27 @@ func TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist(t *testing }) } +// TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_Vars uses Terraform +// configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the +// random provider password resource. This test confirms that the TestCase ExternalProviders +// is being used when ConfigDirectory is set. +func TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestNameDirectory(t), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + ExpectError: regexp.MustCompile(`.*An argument named "numeric" is not expected here.`), + }, + }, + }) +} + // TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist uses Terraform // configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the // random provider password resource. This test confirms that the TestCase ExternalProviders @@ -145,6 +302,27 @@ func TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist(t *testing }) } +// TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_Vars uses Terraform +// configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the +// random provider password resource. This test confirms that the TestCase ExternalProviders +// is being used when ConfigDirectory is set. +func TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestStepDirectory(t), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + ExpectError: regexp.MustCompile(`.*An argument named "numeric" is not expected here.`), + }, + }, + }) +} + // TestTest_ConfigDirectory_StaticDirectory_AttributeDoesNotExist_MultipleFiles uses Terraform // configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the // random provider password resource. This test confirms that the TestCase ExternalProviders @@ -162,6 +340,27 @@ func TestTest_ConfigDirectory_StaticDirectory_AttributeDoesNotExist_MultipleFile }) } +// TestTest_ConfigDirectory_StaticDirectory_AttributeDoesNotExist_MultipleFiles_Vars uses Terraform +// configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the +// random provider password resource. This test confirms that the TestCase ExternalProviders +// is being used when ConfigDirectory is set. +func TestTest_ConfigDirectory_StaticDirectory_AttributeDoesNotExist_MultipleFiles_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory(`fixtures/random_password_3.2.0_multiple_files_vars`), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + ExpectError: regexp.MustCompile(`.*An argument named "numeric" is not expected here.`), + }, + }, + }) +} + // TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles uses Terraform // configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the // random provider password resource. This test confirms that the TestCase ExternalProviders @@ -179,6 +378,27 @@ func TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFi }) } +// TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars uses Terraform +// configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the +// random provider password resource. This test confirms that the TestCase ExternalProviders +// is being used when ConfigDirectory is set. +func TestTest_ConfigDirectory_TestNameDirectory_AttributeDoesNotExist_MultipleFiles_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestNameDirectory(t), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + ExpectError: regexp.MustCompile(`.*An argument named "numeric" is not expected here.`), + }, + }, + }) +} + // TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles uses Terraform // configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the // random provider password resource. This test confirms that the TestCase ExternalProviders @@ -196,6 +416,27 @@ func TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFi }) } +// TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars uses Terraform +// configuration specifying a "numeric" attribute that was introduced in v3.3.0 of the +// random provider password resource. This test confirms that the TestCase ExternalProviders +// is being used when ConfigDirectory is set. +func TestTest_ConfigDirectory_TestStepDirectory_AttributeDoesNotExist_MultipleFiles_Vars(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + Steps: []resource.TestStep{ + { + ConfigDirectory: config.TestStepDirectory(t), + ConfigVariables: config.Variables{ + "length": config.NumberVariable(8), + "numeric": config.BoolVariable(false), + }, + ExpectError: regexp.MustCompile(`.*An argument named "numeric" is not expected here.`), + }, + }, + }) +} + func TestTest_TestStep_ProviderFactories_ConfigDirectory_StaticDirectory(t *testing.T) { t.Parallel() diff --git a/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/provider.tf b/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/provider.tf new file mode 100644 index 000000000..4e7b51e38 --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/provider.tf @@ -0,0 +1,4 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "random" {} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/random.tf b/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/random.tf new file mode 100644 index 000000000..3a652203f --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/random.tf @@ -0,0 +1,8 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/terraform.tf b/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/terraform.tf new file mode 100644 index 000000000..52f5ef4ad --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/terraform.tf @@ -0,0 +1,11 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.2.0" + } + } +} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/vars.tf b/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.2.0_multiple_files_vars/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.2.0_vars/random.tf b/config_directory_test/fixtures/random_password_3.2.0_vars/random.tf new file mode 100644 index 000000000..4aa0668d9 --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.2.0_vars/random.tf @@ -0,0 +1,19 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.2.0" + } + } +} + +provider "random" {} + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.2.0_vars/vars.tf b/config_directory_test/fixtures/random_password_3.2.0_vars/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.2.0_vars/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/provider.tf b/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/provider.tf new file mode 100644 index 000000000..4e7b51e38 --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/provider.tf @@ -0,0 +1,4 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "random" {} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/random.tf b/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/random.tf new file mode 100644 index 000000000..3a652203f --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/random.tf @@ -0,0 +1,8 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/terraform.tf b/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/terraform.tf new file mode 100644 index 000000000..1aaa98022 --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/terraform.tf @@ -0,0 +1,11 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.5.1" + } + } +} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/vars.tf b/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.5.1_multiple_files_vars/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.5.1_vars/random.tf b/config_directory_test/fixtures/random_password_3.5.1_vars/random.tf new file mode 100644 index 000000000..66518ceeb --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.5.1_vars/random.tf @@ -0,0 +1,19 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + random = { + source = "registry.terraform.io/hashicorp/random" + version = "3.5.1" + } + } +} + +provider "random" {} + +resource "random_password" "test" { + length = var.length + + numeric = var.numeric +} \ No newline at end of file diff --git a/config_directory_test/fixtures/random_password_3.5.1_vars/vars.tf b/config_directory_test/fixtures/random_password_3.5.1_vars/vars.tf new file mode 100644 index 000000000..4baf996a2 --- /dev/null +++ b/config_directory_test/fixtures/random_password_3.5.1_vars/vars.tf @@ -0,0 +1,7 @@ +variable "length" { + type = number +} + +variable "numeric" { + type = bool +} \ No newline at end of file diff --git a/go.mod b/go.mod index cb032b6b7..64883a44f 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 github.com/zclconf/go-cty v1.13.2 golang.org/x/crypto v0.11.0 + golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 ) require ( @@ -46,7 +47,7 @@ require ( github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - golang.org/x/mod v0.10.0 // indirect + golang.org/x/mod v0.11.0 // indirect golang.org/x/net v0.11.0 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect diff --git a/go.sum b/go.sum index c6dbdb2dc..7ab7505a8 100644 --- a/go.sum +++ b/go.sum @@ -123,8 +123,10 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= diff --git a/helper/resource/testing.go b/helper/resource/testing.go index 9e74bcb90..7c583788e 100644 --- a/helper/resource/testing.go +++ b/helper/resource/testing.go @@ -515,6 +515,15 @@ type TestStep struct { // an error will be returned. ConfigDirectory config.TestStepConfigFunc + // ConfigVariables is a map defining variables for use in conjunction + // with Terraform configuration. If this map is populated then it + // will be used to assemble an *.auto.tfvars.json which will be + // written into the working directory. Any variables that are + // defined within the Terraform configuration that have a matching + // variable definition in *.auto.tfvars.json will have their value + // substituted when the acceptance test is executed. + ConfigVariables config.Variables + // Check is called after the Config is applied. Use this step to // make your own API calls to check the status of things, and to // inspect the format of the ResourceState itself. diff --git a/helper/resource/testing_new.go b/helper/resource/testing_new.go index 6e84bb14f..815c48584 100644 --- a/helper/resource/testing_new.go +++ b/helper/resource/testing_new.go @@ -111,7 +111,7 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest t.Fatalf("TestCase error creating provider configuration: %s", err) } - err = wd.SetConfig(ctx, config) + err = wd.SetConfig(ctx, config, nil) if err != nil { logging.HelperResourceError(ctx, @@ -258,7 +258,7 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest t.Fatalf("TestStep %d/%d error creating test provider configuration: %s", stepNumber, len(c.Steps), err) } - err = wd.SetConfig(ctx, testStepConfig) + err = wd.SetConfig(ctx, testStepConfig, step.ConfigVariables) if err != nil { logging.HelperResourceError(ctx, @@ -542,7 +542,7 @@ func testIDRefresh(ctx context.Context, t testing.T, c TestCase, wd *plugintest. // Temporarily set the config to a minimal provider config for the refresh // test. After the refresh we can reset it. - err = wd.SetConfig(ctx, testStepConfig) + err = wd.SetConfig(ctx, testStepConfig, step.ConfigVariables) if err != nil { t.Fatalf("Error setting import test config: %s", err) } @@ -567,7 +567,7 @@ func testIDRefresh(ctx context.Context, t testing.T, c TestCase, wd *plugintest. t.Fatalf("Error creating provider configuration for resetting test config: %s", err) } - err = wd.SetConfig(ctx, testStepConfigDefer) + err = wd.SetConfig(ctx, testStepConfigDefer, step.ConfigVariables) if err != nil { t.Fatalf("Error resetting test config: %s", err) diff --git a/helper/resource/testing_new_config.go b/helper/resource/testing_new_config.go index 5e62b02ba..5ada817e2 100644 --- a/helper/resource/testing_new_config.go +++ b/helper/resource/testing_new_config.go @@ -74,7 +74,7 @@ func testStepNewConfig(ctx context.Context, t testing.T, c TestCase, wd *plugint return fmt.Errorf("Error creating config: %w", err) } - err = wd.SetConfig(ctx, testStepConfig) + err = wd.SetConfig(ctx, testStepConfig, step.ConfigVariables) if err != nil { return fmt.Errorf("Error setting config: %w", err) } diff --git a/helper/resource/testing_new_import_state.go b/helper/resource/testing_new_import_state.go index 7940d52c4..39e9baddc 100644 --- a/helper/resource/testing_new_import_state.go +++ b/helper/resource/testing_new_import_state.go @@ -116,7 +116,7 @@ func testStepNewImportState(ctx context.Context, t testing.T, helper *plugintest defer importWd.Close() } - err = importWd.SetConfig(ctx, testStepConfig) + err = importWd.SetConfig(ctx, testStepConfig, step.ConfigVariables) if err != nil { t.Fatalf("Error setting test config: %s", err) } diff --git a/internal/plugintest/working_dir.go b/internal/plugintest/working_dir.go index 2ac42a5e7..59fda2150 100644 --- a/internal/plugintest/working_dir.go +++ b/internal/plugintest/working_dir.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-exec/tfexec" tfjson "github.com/hashicorp/terraform-json" + "github.com/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/internal/logging" "github.com/hashicorp/terraform-plugin-testing/internal/teststep" ) @@ -81,7 +82,7 @@ func (wd *WorkingDir) GetHelper() *Helper { // This must be called at least once before any call to Init, Plan, Apply, or // Destroy to establish the configuration. Any previously-set configuration is // discarded and any saved plan is cleared. -func (wd *WorkingDir) SetConfig(ctx context.Context, cfg teststep.Config) error { +func (wd *WorkingDir) SetConfig(ctx context.Context, cfg teststep.Config, vars config.Variables) error { logging.HelperResourceTrace(ctx, "Setting Terraform configuration", map[string]any{logging.KeyTestTerraformConfiguration: cfg}) outFilename := filepath.Join(wd.baseDir, ConfigFileName) @@ -96,12 +97,20 @@ func (wd *WorkingDir) SetConfig(ctx context.Context, cfg teststep.Config) error // wd.configFilename must be set otherwise wd.Init() will return an error. wd.configFilename = outFilename + // Write configuration err = cfg.Write(ctx, wd.baseDir) if err != nil { return err } + //Write configuration variables + err = vars.Write(wd.baseDir) + + if err != nil { + return err + } + // Changing configuration invalidates any saved plan. err = wd.ClearPlan(ctx)