package schema import ( "fmt" "reflect" "testing" "github.com/hashicorp/terraform/terraform" ) func TestResourceApply_create(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, } called := false r.Create = func(d *ResourceData, m interface{}) error { called = true d.SetId("foo") return nil } var s *terraform.InstanceState = nil d := &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "foo": &terraform.ResourceAttrDiff{ New: "42", }, }, } actual, err := r.Apply(s, d, nil) if err != nil { t.Fatalf("err: %s", err) } if !called { t.Fatal("not called") } expected := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "id": "foo", "foo": "42", }, } if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) } } func TestResourceApply_destroy(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, } called := false r.Delete = func(d *ResourceData, m interface{}) error { called = true return nil } s := &terraform.InstanceState{ ID: "bar", } d := &terraform.InstanceDiff{ Destroy: true, } actual, err := r.Apply(s, d, nil) if err != nil { t.Fatalf("err: %s", err) } if !called { t.Fatal("delete not called") } if actual != nil { t.Fatalf("bad: %#v", actual) } } func TestResourceApply_destroyCreate(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, "tags": &Schema{ Type: TypeMap, Optional: true, Computed: true, }, }, } change := false r.Create = func(d *ResourceData, m interface{}) error { change = d.HasChange("tags") d.SetId("foo") return nil } r.Delete = func(d *ResourceData, m interface{}) error { return nil } var s *terraform.InstanceState = &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "bar", "tags.Name": "foo", }, } d := &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "foo": &terraform.ResourceAttrDiff{ New: "42", RequiresNew: true, }, "tags.Name": &terraform.ResourceAttrDiff{ Old: "foo", New: "foo", RequiresNew: true, }, }, } actual, err := r.Apply(s, d, nil) if err != nil { t.Fatalf("err: %s", err) } if !change { t.Fatal("should have change") } expected := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "id": "foo", "foo": "42", "tags.#": "1", "tags.Name": "foo", }, } if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) } } func TestResourceApply_destroyPartial(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, } r.Delete = func(d *ResourceData, m interface{}) error { d.Set("foo", 42) return fmt.Errorf("some error") } s := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "12", }, } d := &terraform.InstanceDiff{ Destroy: true, } actual, err := r.Apply(s, d, nil) if err == nil { t.Fatal("should error") } expected := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "id": "bar", "foo": "42", }, } if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) } } func TestResourceApply_update(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, } r.Update = func(d *ResourceData, m interface{}) error { d.Set("foo", 42) return nil } s := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "foo": "12", }, } d := &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "foo": &terraform.ResourceAttrDiff{ New: "13", }, }, } actual, err := r.Apply(s, d, nil) if err != nil { t.Fatalf("err: %s", err) } expected := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "id": "foo", "foo": "42", }, } if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) } } func TestResourceApply_updateNoCallback(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, } r.Update = nil s := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "foo": "12", }, } d := &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "foo": &terraform.ResourceAttrDiff{ New: "13", }, }, } actual, err := r.Apply(s, d, nil) if err == nil { t.Fatal("should error") } expected := &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "foo": "12", }, } if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) } } func TestResourceInternalValidate(t *testing.T) { cases := []struct { In *Resource Err bool }{ { nil, true, }, // No optional and no required { &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, Required: true, }, }, }, true, }, } for i, tc := range cases { err := tc.In.InternalValidate() if (err != nil) != tc.Err { t.Fatalf("%d: bad: %s", i, err) } } } func TestResourceRefresh(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, } r.Read = func(d *ResourceData, m interface{}) error { if m != 42 { return fmt.Errorf("meta not passed") } return d.Set("foo", d.Get("foo").(int)+1) } s := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "12", }, } expected := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "id": "bar", "foo": "13", }, } actual, err := r.Refresh(s, 42) if err != nil { t.Fatalf("err: %s", err) } if !reflect.DeepEqual(actual, expected) { t.Fatalf("bad: %#v", actual) } } func TestResourceRefresh_delete(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, } r.Read = func(d *ResourceData, m interface{}) error { d.SetId("") return nil } s := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "12", }, } actual, err := r.Refresh(s, 42) if err != nil { t.Fatalf("err: %s", err) } if actual != nil { t.Fatalf("bad: %#v", actual) } } func TestResourceRefresh_existsError(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, } r.Exists = func(*ResourceData, interface{}) (bool, error) { return false, fmt.Errorf("error") } r.Read = func(d *ResourceData, m interface{}) error { panic("shouldn't be called") } s := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "12", }, } actual, err := r.Refresh(s, 42) if err == nil { t.Fatalf("should error") } if !reflect.DeepEqual(actual, s) { t.Fatalf("bad: %#v", actual) } } func TestResourceRefresh_noExists(t *testing.T) { r := &Resource{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, } r.Exists = func(*ResourceData, interface{}) (bool, error) { return false, nil } r.Read = func(d *ResourceData, m interface{}) error { panic("shouldn't be called") } s := &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "12", }, } actual, err := r.Refresh(s, 42) if err != nil { t.Fatalf("err: %s", err) } if actual != nil { t.Fatalf("should have no state") } }