1221 lines
25 KiB
Go
1221 lines
25 KiB
Go
package test
|
|
|
|
import (
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
|
"github.com/hashicorp/terraform/helper/resource"
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
"github.com/hashicorp/terraform/terraform"
|
|
)
|
|
|
|
func TestResource_basic(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckNoResourceAttr(
|
|
"test_resource.foo", "list.#",
|
|
),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_changedList(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckNoResourceAttr(
|
|
"test_resource.foo", "list.#",
|
|
),
|
|
),
|
|
},
|
|
{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
list = ["a"]
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list.#", "1",
|
|
),
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list.0", "a",
|
|
),
|
|
),
|
|
},
|
|
{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
list = ["a", "b"]
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list.#", "2",
|
|
),
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list.0", "a",
|
|
),
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list.1", "b",
|
|
),
|
|
),
|
|
},
|
|
{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
list = ["b"]
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list.#", "1",
|
|
),
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list.0", "b",
|
|
),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
// Targeted test in TestContext2Apply_ignoreChangesCreate
|
|
func TestResource_ignoreChangesRequired(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
lifecycle {
|
|
ignore_changes = ["required"]
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_ignoreChangesEmpty(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_force_new = "one"
|
|
lifecycle {
|
|
ignore_changes = []
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_force_new = "two"
|
|
lifecycle {
|
|
ignore_changes = []
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_ignoreChangesForceNew(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_force_new = "one"
|
|
lifecycle {
|
|
ignore_changes = ["optional_force_new"]
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_force_new = "two"
|
|
lifecycle {
|
|
ignore_changes = ["optional_force_new"]
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
// Covers specific scenario in #6005, handled by normalizing boolean strings in
|
|
// helper/schema
|
|
func TestResource_ignoreChangesForceNewBoolean(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_force_new = "one"
|
|
optional_bool = true
|
|
lifecycle {
|
|
ignore_changes = ["optional_force_new"]
|
|
}
|
|
}
|
|
`),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_force_new = "two"
|
|
optional_bool = true
|
|
lifecycle {
|
|
ignore_changes = ["optional_force_new"]
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_ignoreChangesMap(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_computed_map = {
|
|
foo = "bar"
|
|
}
|
|
lifecycle {
|
|
ignore_changes = ["optional_computed_map"]
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_computed_map = {
|
|
foo = "bar"
|
|
no = "update"
|
|
}
|
|
lifecycle {
|
|
ignore_changes = ["optional_computed_map"]
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_ignoreChangesDependent(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
count = 2
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
|
|
optional_force_new = "one"
|
|
lifecycle {
|
|
ignore_changes = ["optional_force_new"]
|
|
}
|
|
}
|
|
resource "test_resource" "bar" {
|
|
count = 2
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional = "${element(test_resource.foo.*.id, count.index)}"
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
count = 2
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
|
|
optional_force_new = "two"
|
|
lifecycle {
|
|
ignore_changes = ["optional_force_new"]
|
|
}
|
|
}
|
|
resource "test_resource" "bar" {
|
|
count = 2
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional = "${element(test_resource.foo.*.id, count.index)}"
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_ignoreChangesStillReplaced(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_force_new = "one"
|
|
optional_bool = true
|
|
lifecycle {
|
|
ignore_changes = ["optional_bool"]
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_force_new = "two"
|
|
optional_bool = false
|
|
lifecycle {
|
|
ignore_changes = ["optional_bool"]
|
|
}
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_ignoreChangesCustomizeDiff(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional = "a"
|
|
lifecycle {
|
|
ignore_changes = [optional]
|
|
}
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "planned_computed", "a",
|
|
),
|
|
),
|
|
},
|
|
// On this step, `optional` changes, but `planned_computed`
|
|
// should remain as "a" because we have set `ignore_changes`
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional = "b"
|
|
lifecycle {
|
|
ignore_changes = [optional]
|
|
}
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "planned_computed", "a",
|
|
),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
// Reproduces plan-time panic when the wrong type is interpolated in a list of
|
|
// maps.
|
|
// TODO: this should return a type error, rather than silently setting an empty
|
|
// list
|
|
func TestResource_dataSourceListMapPanic(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "val"
|
|
required_map = {x = "y"}
|
|
list_of_map = "${var.maplist}"
|
|
}
|
|
|
|
variable "maplist" {
|
|
type = "list"
|
|
|
|
default = [
|
|
{a = "b"}
|
|
]
|
|
}
|
|
`),
|
|
ExpectError: nil,
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_dataSourceIndexMapList(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "val"
|
|
|
|
required_map = {
|
|
x = "y"
|
|
}
|
|
|
|
list_of_map = [
|
|
{
|
|
a = "1"
|
|
b = "2"
|
|
},
|
|
{
|
|
c = "3"
|
|
d = "4"
|
|
},
|
|
]
|
|
}
|
|
|
|
output "map_from_list" {
|
|
value = "${test_resource.foo.list_of_map[0]}"
|
|
}
|
|
|
|
output "value_from_map_from_list" {
|
|
value = "${lookup(test_resource.foo.list_of_map[1], "d")}"
|
|
}
|
|
`),
|
|
ExpectError: nil,
|
|
Check: func(s *terraform.State) error {
|
|
root := s.ModuleByPath(addrs.RootModuleInstance)
|
|
mapOut := root.Outputs["map_from_list"].Value
|
|
expectedMapOut := map[string]interface{}{
|
|
"a": "1",
|
|
"b": "2",
|
|
}
|
|
|
|
valueOut := root.Outputs["value_from_map_from_list"].Value
|
|
expectedValueOut := "4"
|
|
|
|
if !reflect.DeepEqual(mapOut, expectedMapOut) {
|
|
t.Fatalf("Expected: %#v\nGot: %#v", expectedMapOut, mapOut)
|
|
}
|
|
if !reflect.DeepEqual(valueOut, expectedValueOut) {
|
|
t.Fatalf("Expected: %#v\nGot: %#v", valueOut, expectedValueOut)
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func testAccCheckResourceDestroy(s *terraform.State) error {
|
|
return nil
|
|
}
|
|
|
|
func TestResource_removeForceNew(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_force_new = "here"
|
|
}
|
|
`),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
}
|
|
`),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_unknownFuncInMap(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "ok"
|
|
required_map = {
|
|
key = "${uuid()}"
|
|
}
|
|
}
|
|
`),
|
|
ExpectNonEmptyPlan: true,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
// Verify that we can destroy when a managed resource references something with
|
|
// a count of 1.
|
|
func TestResource_countRefDestroyError(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
Steps: []resource.TestStep{
|
|
{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "one" {
|
|
count = 1
|
|
required = "ok"
|
|
required_map = {
|
|
key = "val"
|
|
}
|
|
}
|
|
|
|
resource "test_resource" "two" {
|
|
required = test_resource.one[0].id
|
|
required_map = {
|
|
key = "val"
|
|
}
|
|
}
|
|
`),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_emptyMapValue(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "ok"
|
|
required_map = {
|
|
a = "a"
|
|
b = ""
|
|
}
|
|
}
|
|
`),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_updateError(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "first"
|
|
required_map = {
|
|
a = "a"
|
|
}
|
|
}
|
|
`),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "second"
|
|
required_map = {
|
|
a = "a"
|
|
}
|
|
apply_error = "update_error"
|
|
}
|
|
`),
|
|
ExpectError: regexp.MustCompile("update_error"),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_applyError(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "second"
|
|
required_map = {
|
|
a = "a"
|
|
}
|
|
apply_error = "apply_error"
|
|
}
|
|
`),
|
|
ExpectError: regexp.MustCompile("apply_error"),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_emptyStrings(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "second"
|
|
required_map = {
|
|
a = "a"
|
|
}
|
|
|
|
list = [""]
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr("test_resource.foo", "list.0", ""),
|
|
),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "second"
|
|
required_map = {
|
|
a = "a"
|
|
}
|
|
|
|
list = ["", "b"]
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr("test_resource.foo", "list.0", ""),
|
|
resource.TestCheckResourceAttr("test_resource.foo", "list.1", "b"),
|
|
),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "second"
|
|
required_map = {
|
|
a = "a"
|
|
}
|
|
|
|
list = [""]
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr("test_resource.foo", "list.0", ""),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_setDrift(t *testing.T) {
|
|
testProvider := testAccProviders["test"]
|
|
res := testProvider.(*schema.Provider).ResourcesMap["test_resource"]
|
|
|
|
// reset the Read function after the test
|
|
defer func() {
|
|
res.Read = testResourceRead
|
|
}()
|
|
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "first"
|
|
required_map = {
|
|
a = "a"
|
|
}
|
|
set = ["a", "b"]
|
|
}
|
|
`),
|
|
Check: func(s *terraform.State) error {
|
|
return nil
|
|
},
|
|
},
|
|
resource.TestStep{
|
|
PreConfig: func() {
|
|
// update the Read function to return the wrong "set" attribute values.
|
|
res.Read = func(d *schema.ResourceData, meta interface{}) error {
|
|
// update as expected first
|
|
if err := testResourceRead(d, meta); err != nil {
|
|
return err
|
|
}
|
|
d.Set("set", []interface{}{"a", "x"})
|
|
return nil
|
|
}
|
|
},
|
|
// Leave the config, so we can detect the mismatched set values.
|
|
// Updating the config would force the test to pass even if the Read
|
|
// function values were ignored.
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "second"
|
|
required_map = {
|
|
a = "a"
|
|
}
|
|
set = ["a", "b"]
|
|
}
|
|
`),
|
|
ExpectNonEmptyPlan: true,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_optionalComputedMap(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_computed_map = {
|
|
foo = "bar"
|
|
baz = ""
|
|
}
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "optional_computed_map.foo", "bar",
|
|
),
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "optional_computed_map.baz", "",
|
|
),
|
|
),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_computed_map = {}
|
|
}
|
|
`),
|
|
// removing the map from the config should still leave an empty computed map
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "optional_computed_map.%", "0",
|
|
),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_plannedComputed(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "ok"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional = "hi"
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "planned_computed", "hi",
|
|
),
|
|
),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "ok"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional = "changed"
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "planned_computed", "changed",
|
|
),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestDiffApply_map(t *testing.T) {
|
|
resSchema := map[string]*schema.Schema{
|
|
"map": {
|
|
Type: schema.TypeMap,
|
|
Optional: true,
|
|
Computed: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
}
|
|
|
|
priorAttrs := map[string]string{
|
|
"id": "ok",
|
|
"map.%": "2",
|
|
"map.foo": "bar",
|
|
"map.bar": "",
|
|
}
|
|
|
|
diff := &terraform.InstanceDiff{
|
|
Attributes: map[string]*terraform.ResourceAttrDiff{
|
|
"map.foo": &terraform.ResourceAttrDiff{Old: "bar", New: "", NewRemoved: true},
|
|
"map.bar": &terraform.ResourceAttrDiff{Old: "", New: "", NewRemoved: true},
|
|
},
|
|
}
|
|
|
|
newAttrs, err := diff.Apply(priorAttrs, (&schema.Resource{Schema: resSchema}).CoreConfigSchema())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expect := map[string]string{
|
|
"id": "ok",
|
|
"map.%": "0",
|
|
}
|
|
|
|
if !reflect.DeepEqual(newAttrs, expect) {
|
|
t.Fatalf("expected:%#v got:%#v", expect, newAttrs)
|
|
}
|
|
}
|
|
|
|
func TestResource_dependsComputed(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
variable "change" {
|
|
default = false
|
|
}
|
|
|
|
resource "test_resource" "foo" {
|
|
required = "ok"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional = var.change ? "after" : ""
|
|
}
|
|
|
|
resource "test_resource" "bar" {
|
|
count = var.change ? 1 : 0
|
|
required = test_resource.foo.planned_computed
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
}
|
|
`),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
variable "change" {
|
|
default = true
|
|
}
|
|
|
|
resource "test_resource" "foo" {
|
|
required = "ok"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional = var.change ? "after" : ""
|
|
}
|
|
|
|
resource "test_resource" "bar" {
|
|
count = var.change ? 1 : 0
|
|
required = test_resource.foo.planned_computed
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
}
|
|
`),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_optionalComputedBool(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
}
|
|
`),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_replacedOptionalComputed(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource_nested" "a" {
|
|
}
|
|
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_computed = test_resource_nested.a.id
|
|
}
|
|
`),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource_nested" "b" {
|
|
}
|
|
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional_computed = test_resource_nested.b.id
|
|
}
|
|
`),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_floatInIntAttr(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
int = 40.2
|
|
}
|
|
`),
|
|
ExpectError: regexp.MustCompile(`must be a whole number, got 40.2`),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestResource_unsetNil(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
optional = "a"
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr("test_resource.foo", "optional", "a"),
|
|
),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr("test_resource.foo", "optional", ""),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
// Verify we can use use numeric indices in `ignore_changes` paths.
|
|
func TestResource_ignoreChangesIndex(t *testing.T) {
|
|
resource.UnitTest(t, resource.TestCase{
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckResourceDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
list_of_map = [
|
|
{
|
|
a = "b"
|
|
}
|
|
]
|
|
|
|
lifecycle {
|
|
ignore_changes = [list_of_map[0]["a"]]
|
|
}
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list_of_map.0.a", "b",
|
|
),
|
|
),
|
|
},
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
list_of_map = [
|
|
{
|
|
a = "c"
|
|
}
|
|
]
|
|
|
|
lifecycle {
|
|
ignore_changes = [list_of_map[0]["a"]]
|
|
}
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list_of_map.0.a", "b",
|
|
),
|
|
),
|
|
},
|
|
// set ignore_changes to a prefix of the changed value
|
|
resource.TestStep{
|
|
Config: strings.TrimSpace(`
|
|
resource "test_resource" "foo" {
|
|
required = "yep"
|
|
required_map = {
|
|
key = "value"
|
|
}
|
|
list_of_map = [
|
|
{
|
|
a = "d"
|
|
}
|
|
]
|
|
|
|
lifecycle {
|
|
ignore_changes = [list_of_map[0]]
|
|
}
|
|
}
|
|
`),
|
|
Check: resource.ComposeTestCheckFunc(
|
|
resource.TestCheckResourceAttr(
|
|
"test_resource.foo", "list_of_map.0.a", "b",
|
|
),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|