package test import ( "errors" "fmt" "regexp" "strings" "testing" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" ) func TestResourceNestedSet_basic(t *testing.T) { resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { single { value = "bar" } } `), }, }, }) } // The set should not be generated because of it's computed value func TestResourceNestedSet_noSet(t *testing.T) { checkFunc := func(s *terraform.State) error { root := s.ModuleByPath(addrs.RootModuleInstance) res := root.Resources["test_resource_nested_set.foo"] for k, v := range res.Primary.Attributes { if strings.HasPrefix(k, "single") && k != "single.#" { return fmt.Errorf("unexpected set value: %s:%s", k, v) } } return nil } resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { } `), Check: checkFunc, }, }, }) } // the empty type_list must be passed to the provider with 1 nil element func TestResourceNestedSet_emptyBlock(t *testing.T) { checkFunc := func(s *terraform.State) error { root := s.ModuleByPath(addrs.RootModuleInstance) res := root.Resources["test_resource_nested_set.foo"] for k, v := range res.Primary.Attributes { if strings.HasPrefix(k, "type_list") && v != "1" { return fmt.Errorf("unexpected set value: %s:%s", k, v) } } return nil } resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { type_list { } } `), Check: checkFunc, }, }, }) } func TestResourceNestedSet_emptyNestedListBlock(t *testing.T) { checkFunc := func(s *terraform.State) error { root := s.ModuleByPath(addrs.RootModuleInstance) res := root.Resources["test_resource_nested_set.foo"] found := false for k := range res.Primary.Attributes { if !regexp.MustCompile(`^with_list\.\d+\.list_block\.`).MatchString(k) { continue } found = true } if !found { return fmt.Errorf("with_list.X.list_block not found") } return nil } resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { with_list { required = "ok" list_block { } } } `), Check: checkFunc, }, }, }) } func TestResourceNestedSet_emptyNestedList(t *testing.T) { checkFunc := func(s *terraform.State) error { root := s.ModuleByPath(addrs.RootModuleInstance) res := root.Resources["test_resource_nested_set.foo"] found := false for k, v := range res.Primary.Attributes { if regexp.MustCompile(`^with_list\.\d+\.list\.#$`).MatchString(k) { found = true if v != "0" { return fmt.Errorf("expected empty list: %s, got %s", k, v) } break } } if !found { return fmt.Errorf("with_list.X.nested_list not found") } return nil } resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { with_list { required = "ok" list = [] } } `), Check: checkFunc, }, }, }) } func TestResourceNestedSet_addRemove(t *testing.T) { var id string checkFunc := func(s *terraform.State) error { root := s.ModuleByPath(addrs.RootModuleInstance) res := root.Resources["test_resource_nested_set.foo"] if res.Primary.ID == id { return errors.New("expected new resource") } id = res.Primary.ID return nil } resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { single { value = "bar" } } `), Check: resource.ComposeTestCheckFunc( checkFunc, resource.TestCheckResourceAttr( "test_resource_nested_set.foo", "single.#", "1", ), // the hash of single seems to change here, so we're not // going to test for "value" directly // FIXME: figure out why the set hash changes ), }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { } `), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( "test_resource_nested_set.foo", "single.#", "0", ), checkFunc, ), }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { single { value = "bar" } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { single { value = "bar" optional = "baz" } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { } `), Check: checkFunc, }, }, }) } func TestResourceNestedSet_multiAddRemove(t *testing.T) { checkFunc := func(s *terraform.State) error { return nil } resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { multi { optional = "bar" } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { multi { set { required = "val" } } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { multi { set { required = "new" } } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { multi { set { required = "new" optional_int = 3 } } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { single { value = "bar" optional = "baz" } multi { set { required = "new" optional_int = 3 } } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { optional = true single { value = "bar" optional = "baz" } multi { set { required = "new" optional_int = 3 } } } `), Check: checkFunc, }, }, }) } func TestResourceNestedSet_forceNewEmptyString(t *testing.T) { var id string step := 0 checkFunc := func(s *terraform.State) error { root := s.ModuleByPath(addrs.RootModuleInstance) res := root.Resources["test_resource_nested_set.foo"] defer func() { step++ id = res.Primary.ID }() if step == 2 && res.Primary.ID == id { // setting an empty string currently does not trigger ForceNew, but // it should in the future. return nil } if res.Primary.ID == id { return errors.New("expected new resource") } return nil } resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { multi { set { required = "val" } } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { multi { set { required = "" } } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { force_new = "" } `), Check: checkFunc, }, }, }) } func TestResourceNestedSet_setWithList(t *testing.T) { checkFunc := func(s *terraform.State) error { return nil } resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { with_list { required = "bar" list = ["initial value"] } } `), Check: checkFunc, }, resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { with_list { required = "bar" list = ["second value"] } } `), Check: checkFunc, }, }, }) } // This is the same as forceNewEmptyString, but we start with the empty value, // instead of changing it. func TestResourceNestedSet_nestedSetEmptyString(t *testing.T) { resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { multi { set { required = "" } } } `), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( "test_resource_nested_set.foo", "multi.529860700.set.4196279896.required", "", ), ), }, }, }) } func TestResourceNestedSet_emptySet(t *testing.T) { resource.UnitTest(t, resource.TestCase{ Providers: testAccProviders, CheckDestroy: testAccCheckResourceDestroy, Steps: []resource.TestStep{ resource.TestStep{ Config: strings.TrimSpace(` resource "test_resource_nested_set" "foo" { multi { } } `), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( "test_resource_nested_set.foo", "multi.#", "1", ), ), }, }, }) }