func TestProviderConfigure(t *testing.T) { var expectedKey string var expectedEmail string if v := os.Getenv("HEROKU_EMAIL"); v != "" { expectedEmail = v } else { expectedEmail = "foo" } if v := os.Getenv("HEROKU_API_KEY"); v != "" { expectedKey = v } else { expectedKey = "foo" } raw := map[string]interface{}{ "api_key": expectedKey, "email": expectedEmail, } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } rp := Provider() err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } }
func TestResourceProvider_Configure(t *testing.T) { rp := new(ResourceProvider) raw := map[string]interface{}{ "address": "demo.consul.io:80", "datacenter": "nyc1", } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } expected := Config{ Address: "demo.consul.io:80", Datacenter: "nyc1", } if !reflect.DeepEqual(rp.Config, expected) { t.Fatalf("bad: %#v", rp.Config) } }
func TestResourceProvider_Configure(t *testing.T) { rp := new(ResourceProvider) raw := map[string]interface{}{ "token": "foo", } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } expected := Config{ Token: "foo", } if !reflect.DeepEqual(rp.Config, expected) { t.Fatalf("bad: %#v", rp.Config) } }
func TestResourceProvider_Configure(t *testing.T) { rp := new(ResourceProvider) raw := map[string]interface{}{ "access_key": "foo", "secret_key": "bar", "region": "us-east-1", } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } expected := Config{ AccessKey: "foo", SecretKey: "bar", Region: "us-east-1", } if !reflect.DeepEqual(rp.Config, expected) { t.Fatalf("bad: %#v", rp.Config) } }
func TestProviderValidate(t *testing.T) { cases := []struct { P *Provider Config map[string]interface{} Err bool }{ { P: &Provider{ Schema: map[string]*Schema{ "foo": &Schema{}, }, }, Config: nil, Err: true, }, } for i, tc := range cases { c, err := config.NewRawConfig(tc.Config) if err != nil { t.Fatalf("err: %s", err) } _, es := tc.P.Validate(terraform.NewResourceConfig(c)) if len(es) > 0 != tc.Err { t.Fatalf("%d: %#v", i, es) } } }
func TestProviderConfigure(t *testing.T) { var expectedKey string if v := os.Getenv("MAILGUN_API_KEY"); v != "" { expectedKey = v } else { expectedKey = "foo" } raw := map[string]interface{}{ "api_key": expectedKey, } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } rp := Provider() err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } config := rp.Meta().(*mailgun.Client) if config.ApiKey != expectedKey { t.Fatalf("bad: %#v", config) } }
func TestProviderConfigure(t *testing.T) { p := Provider().(*schema.Provider) raw, err := config.NewRawConfig(map[string]interface{}{ "account": helpers.TestAccount, "key": helpers.TestKeyFile, "key_id": helpers.TestKeyID, "url": "https://us-east-1.api.joyentcloud.com", }) if err != nil { t.Fatal(err) } providerConfig := terraform.NewResourceConfig(raw) assert.Nil(t, p.Meta()) assert.Nil(t, p.Configure(providerConfig)) config, ok := p.Meta().(*Config) if assert.True(t, ok) { assert.NotNil(t, config) assert.Equal(t, config.Account, helpers.TestAccount) assert.Equal(t, config.Key, helpers.TestKeyFile) assert.Equal(t, config.KeyID, helpers.TestKeyID) assert.Equal(t, config.URL, "https://us-east-1.api.joyentcloud.com") } }
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig { r, err := config.NewRawConfig(c) if err != nil { t.Fatalf("bad: %s", err) } return terraform.NewResourceConfig(r) }
func testConfigInterpolate( t *testing.T, raw map[string]interface{}, vs map[string]ast.Variable) *terraform.ResourceConfig { rc, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } if len(vs) > 0 { if err := rc.Interpolate(vs); err != nil { t.Fatalf("err: %s", err) } } return terraform.NewResourceConfig(rc) }
func TestAzure_providerConfigure(t *testing.T) { home, err := homedir.Dir() if err != nil { t.Fatalf("Error fetching homedir: %s", err) } fh, err := ioutil.TempFile(home, "tf-test-home") if err != nil { t.Fatalf("Error creating homedir-based temporary file: %s", err) } defer os.Remove(fh.Name()) _, err = io.WriteString(fh, testAzurePublishSettingsStr) if err != nil { t.Fatalf("err: %s", err) } fh.Close() r := strings.NewReplacer(home, "~") homePath := r.Replace(fh.Name()) cases := []struct { SettingsFile string // String of XML or a path to an XML file NilMeta bool // whether meta is expected to be nil }{ {testAzurePublishSettingsStr, false}, {homePath, false}, } for _, tc := range cases { rp := Provider() raw := map[string]interface{}{ "settings_file": tc.SettingsFile, } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) meta := rp.(*schema.Provider).Meta() if (meta == nil) != tc.NilMeta { t.Fatalf("expected NilMeta: %t, got meta: %#v, settings_file: %q", tc.NilMeta, meta, tc.SettingsFile) } } }
func TestAzure_providerConfigure(t *testing.T) { rp := Provider() raw := map[string]interface{}{ "publish_settings": testAzurePublishSettingsStr, } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) meta := rp.(*schema.Provider).Meta() if meta == nil { t.Fatalf("Expected metadata, got nil: err: %s", err) } }
func TestResourceProvider_Configure(t *testing.T) { rp := Provider() raw := map[string]interface{}{ "address": "demo.consul.io:80", "datacenter": "nyc3", } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } }
func TestResourceProvider_ConfigureBadRegion(t *testing.T) { rp := new(ResourceProvider) raw := map[string]interface{}{ "access_key": "foo", "secret_key": "bar", "region": "blah", } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err == nil { t.Fatalf("should have err: bad region") } }
func TestResourceProvider_Configure(t *testing.T) { rp := new(ResourceProvider) var expectedToken string var expectedEmail string if v := os.Getenv("DNSIMPLE_EMAIL"); v != "" { expectedEmail = v } else { expectedEmail = "foo" } if v := os.Getenv("DNSIMPLE_TOKEN"); v != "" { expectedToken = v } else { expectedToken = "foo" } raw := map[string]interface{}{ "token": expectedToken, "email": expectedEmail, } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } expected := Config{ Token: expectedToken, Email: expectedEmail, } if !reflect.DeepEqual(rp.Config, expected) { t.Fatalf("bad: %#v", rp.Config) } }
func TestResourceProvider_Configure(t *testing.T) { rp := new(ResourceProvider) var expectedKey string var expectedEmail string if v := os.Getenv("HEROKU_EMAIL"); v != "" { expectedEmail = v } else { expectedEmail = "foo" } if v := os.Getenv("HEROKU_API_KEY"); v != "" { expectedKey = v } else { expectedKey = "foo" } raw := map[string]interface{}{ "api_key": expectedKey, "email": expectedEmail, } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } expected := Config{ APIKey: expectedKey, Email: expectedEmail, } if !reflect.DeepEqual(rp.Config, expected) { t.Fatalf("bad: %#v", rp.Config) } }
func testConfig( t *testing.T, c map[string]interface{}, vs map[string]string) *terraform.ResourceConfig { rc, err := config.NewRawConfig(c) if err != nil { t.Fatalf("err: %s", err) } if len(vs) > 0 { vars := make(map[string]ast.Variable) for k, v := range vs { vars[k] = ast.Variable{Value: v, Type: ast.TypeString} } if err := rc.Interpolate(vars); err != nil { t.Fatalf("err: %s", err) } } return terraform.NewResourceConfig(rc) }
func TestResourceProvider_ConfigureTLS(t *testing.T) { rp := Provider() raw := map[string]interface{}{ "address": "demo.consul.io:80", "ca_file": "test-fixtures/cacert.pem", "cert_file": "test-fixtures/usercert.pem", "datacenter": "nyc3", "key_file": "test-fixtures/userkey.pem", "scheme": "https", } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } }
func TestProviderValidateResource(t *testing.T) { cases := []struct { P *Provider Type string Config map[string]interface{} Err bool }{ { P: &Provider{}, Type: "foo", Config: nil, Err: true, }, { P: &Provider{ ResourcesMap: map[string]*Resource{ "foo": &Resource{}, }, }, Type: "foo", Config: nil, Err: false, }, } for i, tc := range cases { c, err := config.NewRawConfig(tc.Config) if err != nil { t.Fatalf("err: %s", err) } _, es := tc.P.ValidateResource(tc.Type, terraform.NewResourceConfig(c)) if len(es) > 0 != tc.Err { t.Fatalf("%d: %#v", i, es) } } }
func TestProviderConfigure(t *testing.T) { var expectedUser string var expectedPassword string var expectedKey string var expectedAccountEmail string if v := os.Getenv("PINGDOM_USER"); v != "" { expectedUser = v } else { expectedUser = "******" } if v := os.Getenv("PINGDOM_PASSWORD"); v != "" { expectedPassword = v } else { expectedPassword = "******" } if v := os.Getenv("PINGDOM_API_KEY"); v != "" { expectedKey = v } else { expectedKey = "foo" } if v := os.Getenv("PINGDOM_ACCOUNT_EMAIL"); v != "" { expectedAccountEmail = v } else { expectedAccountEmail = "foo" } raw := map[string]interface{}{ "user": expectedUser, "password": expectedPassword, "api_key": expectedKey, "account_email": expectedAccountEmail, } rawConfig, err := config.NewRawConfig(raw) if err != nil { t.Fatalf("err: %s", err) } rp := Provider().(*schema.Provider) err = rp.Configure(terraform.NewResourceConfig(rawConfig)) if err != nil { t.Fatalf("err: %s", err) } config := rp.Meta().(*pingdom.Client) if config.User != expectedUser { t.Fatalf("bad: %#v", config) } if config.Password != expectedPassword { t.Fatalf("bad: %#v", config) } if config.APIKey != expectedKey { t.Fatalf("bad: %#v", config) } }
func TestSchemaMap_Diff(t *testing.T) { cases := []struct { Schema map[string]*Schema State *terraform.InstanceState Config map[string]interface{} ConfigVariables map[string]string Diff *terraform.InstanceDiff Err bool }{ /* * String decode */ // #0 { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{ "availability_zone": "foo", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", New: "foo", RequiresNew: true, }, }, }, Err: false, }, // #1 { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{}, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", NewComputed: true, RequiresNew: true, }, }, }, Err: false, }, // #2 { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, State: &terraform.InstanceState{ ID: "foo", }, Config: map[string]interface{}{}, Diff: nil, Err: false, }, // #3 Computed, but set in config { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", }, }, Config: map[string]interface{}{ "availability_zone": "bar", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "foo", New: "bar", }, }, }, Err: false, }, // #4 Default { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Default: "foo", }, }, State: nil, Config: nil, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", New: "foo", }, }, }, Err: false, }, // #5 DefaultFunc, value { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, DefaultFunc: func() (interface{}, error) { return "foo", nil }, }, }, State: nil, Config: nil, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", New: "foo", }, }, }, Err: false, }, // #6 DefaultFunc, configuration set { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, DefaultFunc: func() (interface{}, error) { return "foo", nil }, }, }, State: nil, Config: map[string]interface{}{ "availability_zone": "bar", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", New: "bar", }, }, }, Err: false, }, // #7 String with StateFunc { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, StateFunc: func(a interface{}) string { return a.(string) + "!" }, }, }, State: nil, Config: map[string]interface{}{ "availability_zone": "foo", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", New: "foo!", NewExtra: "foo", }, }, }, Err: false, }, // #8 Variable (just checking) { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, }, }, State: nil, Config: map[string]interface{}{ "availability_zone": "${var.foo}", }, ConfigVariables: map[string]string{ "var.foo": "bar", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", New: "bar", }, }, }, Err: false, }, // #9 Variable computed { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, }, }, State: nil, Config: map[string]interface{}{ "availability_zone": "${var.foo}", }, ConfigVariables: map[string]string{ "var.foo": config.UnknownVariableValue, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", New: "${var.foo}", }, }, }, Err: false, }, /* * Int decode */ // #10 { Schema: map[string]*Schema{ "port": &Schema{ Type: TypeInt, Optional: true, Computed: true, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{ "port": 27, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "port": &terraform.ResourceAttrDiff{ Old: "", New: "27", RequiresNew: true, }, }, }, Err: false, }, /* * Bool decode */ // #11 { Schema: map[string]*Schema{ "port": &Schema{ Type: TypeBool, Optional: true, Computed: true, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{ "port": false, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "port": &terraform.ResourceAttrDiff{ Old: "", New: "0", RequiresNew: true, }, }, }, Err: false, }, /* * Bool */ // #12 { Schema: map[string]*Schema{ "delete": &Schema{ Type: TypeBool, Optional: true, Default: false, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "delete": "false", }, }, Config: nil, Diff: nil, Err: false, }, /* * List decode */ // #13 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{1, 2, 5}, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", New: "3", }, "ports.0": &terraform.ResourceAttrDiff{ Old: "", New: "1", }, "ports.1": &terraform.ResourceAttrDiff{ Old: "", New: "2", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, // #14 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{1, "${var.foo}"}, }, ConfigVariables: map[string]string{ "var.foo": "2" + config.InterpSplitDelim + "5", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", New: "3", }, "ports.0": &terraform.ResourceAttrDiff{ Old: "", New: "1", }, "ports.1": &terraform.ResourceAttrDiff{ Old: "", New: "2", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, // #15 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{1, "${var.foo}"}, }, ConfigVariables: map[string]string{ "var.foo": config.UnknownVariableValue + config.InterpSplitDelim + "5", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", New: "", NewComputed: true, }, }, }, Err: false, }, // #16 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "1", "ports.1": "2", "ports.2": "5", }, }, Config: map[string]interface{}{ "ports": []interface{}{1, 2, 5}, }, Diff: nil, Err: false, }, // #17 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "1", "ports.1": "2", }, }, Config: map[string]interface{}{ "ports": []interface{}{1, 2, 5}, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "2", New: "3", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, // #18 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{1, 2, 5}, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", New: "3", RequiresNew: true, }, "ports.0": &terraform.ResourceAttrDiff{ Old: "", New: "1", RequiresNew: true, }, "ports.1": &terraform.ResourceAttrDiff{ Old: "", New: "2", RequiresNew: true, }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "5", RequiresNew: true, }, }, }, Err: false, }, // #19 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Optional: true, Computed: true, Elem: &Schema{Type: TypeInt}, }, }, State: nil, Config: map[string]interface{}{}, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "", NewComputed: true, }, }, }, Err: false, }, /* * Set */ // #20 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{5, 2, 1}, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", New: "3", }, "ports.1": &terraform.ResourceAttrDiff{ Old: "", New: "1", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "2", }, "ports.5": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, // #21 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Computed: true, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "0", }, }, Config: nil, Diff: nil, Err: false, }, // #22 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Optional: true, Computed: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: nil, Config: nil, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "", NewComputed: true, }, }, }, Err: false, }, // #23 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{"${var.foo}", 1}, }, ConfigVariables: map[string]string{ "var.foo": "2" + config.InterpSplitDelim + "5", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", New: "3", }, "ports.1": &terraform.ResourceAttrDiff{ Old: "", New: "1", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "2", }, "ports.5": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, // #24 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{1, "${var.foo}"}, }, ConfigVariables: map[string]string{ "var.foo": config.UnknownVariableValue + config.InterpSplitDelim + "5", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "", New: "", NewComputed: true, }, }, }, Err: false, }, // #25 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.1": "1", "ports.2": "2", }, }, Config: map[string]interface{}{ "ports": []interface{}{5, 2, 1}, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "2", New: "3", }, "ports.1": &terraform.ResourceAttrDiff{ Old: "1", New: "1", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "2", New: "2", }, "ports.5": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, // #26 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "ports.#": "2", "ports.1": "1", "ports.2": "2", }, }, Config: map[string]interface{}{}, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "2", New: "0", }, }, }, Err: false, }, // #27 { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Optional: true, Computed: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "bar", "ports.#": "1", "ports.80": "80", }, }, Config: map[string]interface{}{}, Diff: nil, Err: false, }, // #28 { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeSet, Required: true, Elem: &Resource{ Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Optional: true, Elem: &Schema{Type: TypeInt}, }, }, }, Set: func(v interface{}) int { m := v.(map[string]interface{}) ps := m["ports"].([]interface{}) result := 0 for _, p := range ps { result += p.(int) } return result }, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "ingress.#": "2", "ingress.80.ports.#": "1", "ingress.80.ports.0": "80", "ingress.443.ports.#": "1", "ingress.443.ports.0": "443", }, }, Config: map[string]interface{}{ "ingress": []map[string]interface{}{ map[string]interface{}{ "ports": []interface{}{443}, }, map[string]interface{}{ "ports": []interface{}{80}, }, }, }, Diff: nil, Err: false, }, /* * List of structure decode */ // #29 { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Required: true, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, State: nil, Config: map[string]interface{}{ "ingress": []interface{}{ map[string]interface{}{ "from": 8080, }, }, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ingress.#": &terraform.ResourceAttrDiff{ Old: "0", New: "1", }, "ingress.0.from": &terraform.ResourceAttrDiff{ Old: "", New: "8080", }, }, }, Err: false, }, /* * ComputedWhen */ // #30 { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Computed: true, ComputedWhen: []string{"port"}, }, "port": &Schema{ Type: TypeInt, Optional: true, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", "port": "80", }, }, Config: map[string]interface{}{ "port": 80, }, Diff: nil, Err: false, }, // #31 { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Computed: true, ComputedWhen: []string{"port"}, }, "port": &Schema{ Type: TypeInt, Optional: true, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "port": "80", }, }, Config: map[string]interface{}{ "port": 80, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ NewComputed: true, }, }, }, Err: false, }, /* TODO { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Computed: true, ComputedWhen: []string{"port"}, }, "port": &Schema{ Type: TypeInt, Optional: true, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "foo", "port": "80", }, }, Config: map[string]interface{}{ "port": 8080, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "foo", NewComputed: true, }, "port": &terraform.ResourceAttrDiff{ Old: "80", New: "8080", }, }, }, Err: false, }, */ /* * Maps */ // #32 { Schema: map[string]*Schema{ "config_vars": &Schema{ Type: TypeMap, }, }, State: nil, Config: map[string]interface{}{ "config_vars": []interface{}{ map[string]interface{}{ "bar": "baz", }, }, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.#": &terraform.ResourceAttrDiff{ Old: "0", New: "1", }, "config_vars.bar": &terraform.ResourceAttrDiff{ Old: "", New: "baz", }, }, }, Err: false, }, // #33 { Schema: map[string]*Schema{ "config_vars": &Schema{ Type: TypeMap, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.foo": "bar", }, }, Config: map[string]interface{}{ "config_vars": []interface{}{ map[string]interface{}{ "bar": "baz", }, }, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.foo": &terraform.ResourceAttrDiff{ Old: "bar", NewRemoved: true, }, "config_vars.bar": &terraform.ResourceAttrDiff{ Old: "", New: "baz", }, }, }, Err: false, }, // #34 { Schema: map[string]*Schema{ "vars": &Schema{ Type: TypeMap, Optional: true, Computed: true, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "vars.foo": "bar", }, }, Config: map[string]interface{}{ "vars": []interface{}{ map[string]interface{}{ "bar": "baz", }, }, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "vars.foo": &terraform.ResourceAttrDiff{ Old: "bar", New: "", NewRemoved: true, }, "vars.bar": &terraform.ResourceAttrDiff{ Old: "", New: "baz", }, }, }, Err: false, }, // #35 { Schema: map[string]*Schema{ "vars": &Schema{ Type: TypeMap, Computed: true, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "vars.foo": "bar", }, }, Config: nil, Diff: nil, Err: false, }, // #36 { Schema: map[string]*Schema{ "config_vars": &Schema{ Type: TypeList, Elem: &Schema{Type: TypeMap}, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "1", "config_vars.0.foo": "bar", }, }, Config: map[string]interface{}{ "config_vars": []interface{}{ map[string]interface{}{ "bar": "baz", }, }, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.0.foo": &terraform.ResourceAttrDiff{ Old: "bar", NewRemoved: true, }, "config_vars.0.bar": &terraform.ResourceAttrDiff{ Old: "", New: "baz", }, }, }, Err: false, }, // #37 { Schema: map[string]*Schema{ "config_vars": &Schema{ Type: TypeList, Elem: &Schema{Type: TypeMap}, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "config_vars.#": "1", "config_vars.0.foo": "bar", "config_vars.0.bar": "baz", }, }, Config: map[string]interface{}{}, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.#": &terraform.ResourceAttrDiff{ Old: "1", New: "0", }, "config_vars.0.#": &terraform.ResourceAttrDiff{ Old: "2", New: "0", }, "config_vars.0.foo": &terraform.ResourceAttrDiff{ Old: "bar", NewRemoved: true, }, "config_vars.0.bar": &terraform.ResourceAttrDiff{ Old: "baz", NewRemoved: true, }, }, }, Err: false, }, /* * ForceNews */ // #38 { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, ForceNew: true, }, "address": &Schema{ Type: TypeString, Optional: true, Computed: true, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "bar", "address": "foo", }, }, Config: map[string]interface{}{ "availability_zone": "foo", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "bar", New: "foo", RequiresNew: true, }, "address": &terraform.ResourceAttrDiff{ Old: "foo", New: "", NewComputed: true, }, }, }, Err: false, }, // #39 Set { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, ForceNew: true, }, "ports": &Schema{ Type: TypeSet, Optional: true, Computed: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "availability_zone": "bar", "ports.#": "1", "ports.80": "80", }, }, Config: map[string]interface{}{ "availability_zone": "foo", }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "bar", New: "foo", RequiresNew: true, }, "ports.#": &terraform.ResourceAttrDiff{ Old: "1", New: "", NewComputed: true, }, }, }, Err: false, }, // #40 Set { Schema: map[string]*Schema{ "instances": &Schema{ Type: TypeSet, Elem: &Schema{Type: TypeString}, Optional: true, Computed: true, Set: func(v interface{}) int { return len(v.(string)) }, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "instances.#": "0", }, }, Config: map[string]interface{}{ "instances": []interface{}{"${var.foo}"}, }, ConfigVariables: map[string]string{ "var.foo": config.UnknownVariableValue, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "instances.#": &terraform.ResourceAttrDiff{ Old: "0", NewComputed: true, }, }, }, Err: false, }, // #41 Set { Schema: map[string]*Schema{ "route": &Schema{ Type: TypeSet, Optional: true, Elem: &Resource{ Schema: map[string]*Schema{ "index": &Schema{ Type: TypeInt, Required: true, }, "gateway": &Schema{ Type: TypeString, Optional: true, }, }, }, Set: func(v interface{}) int { m := v.(map[string]interface{}) return m["index"].(int) }, }, }, State: nil, Config: map[string]interface{}{ "route": []map[string]interface{}{ map[string]interface{}{ "index": "1", "gateway": "${var.foo}", }, }, }, ConfigVariables: map[string]string{ "var.foo": config.UnknownVariableValue, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "route.#": &terraform.ResourceAttrDiff{ Old: "0", New: "1", }, "route.~1.index": &terraform.ResourceAttrDiff{ Old: "", New: "1", }, "route.~1.gateway": &terraform.ResourceAttrDiff{ Old: "", New: "${var.foo}", }, }, }, Err: false, }, // #42 Set { Schema: map[string]*Schema{ "route": &Schema{ Type: TypeSet, Optional: true, Elem: &Resource{ Schema: map[string]*Schema{ "index": &Schema{ Type: TypeInt, Required: true, }, "gateway": &Schema{ Type: TypeSet, Optional: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, }, Set: func(v interface{}) int { m := v.(map[string]interface{}) return m["index"].(int) }, }, }, State: nil, Config: map[string]interface{}{ "route": []map[string]interface{}{ map[string]interface{}{ "index": "1", "gateway": []interface{}{ "${var.foo}", }, }, }, }, ConfigVariables: map[string]string{ "var.foo": config.UnknownVariableValue, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "route.#": &terraform.ResourceAttrDiff{ Old: "0", New: "1", }, "route.~1.index": &terraform.ResourceAttrDiff{ Old: "", New: "1", }, "route.~1.gateway.#": &terraform.ResourceAttrDiff{ Old: "", NewComputed: true, }, }, }, Err: false, }, // #43 - Computed maps { Schema: map[string]*Schema{ "vars": &Schema{ Type: TypeMap, Computed: true, }, }, State: nil, Config: nil, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "vars.#": &terraform.ResourceAttrDiff{ Old: "", NewComputed: true, }, }, }, Err: false, }, // #44 - Computed maps { Schema: map[string]*Schema{ "vars": &Schema{ Type: TypeMap, Computed: true, }, }, State: &terraform.InstanceState{ Attributes: map[string]string{ "vars.#": "0", }, }, Config: map[string]interface{}{ "vars": map[string]interface{}{ "bar": "${var.foo}", }, }, ConfigVariables: map[string]string{ "var.foo": config.UnknownVariableValue, }, Diff: &terraform.InstanceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "vars.#": &terraform.ResourceAttrDiff{ Old: "", NewComputed: true, }, }, }, Err: false, }, // #45 - Empty { Schema: map[string]*Schema{}, State: &terraform.InstanceState{}, Config: map[string]interface{}{}, Diff: nil, Err: false, }, } for i, tc := range cases { c, err := config.NewRawConfig(tc.Config) if err != nil { t.Fatalf("#%d err: %s", i, err) } if len(tc.ConfigVariables) > 0 { if err := c.Interpolate(tc.ConfigVariables); err != nil { t.Fatalf("#%d err: %s", i, err) } } d, err := schemaMap(tc.Schema).Diff( tc.State, terraform.NewResourceConfig(c)) if (err != nil) != tc.Err { t.Fatalf("#%d err: %s", i, err) } if !reflect.DeepEqual(tc.Diff, d) { t.Fatalf("#%d: bad:\n\n%#v", i, d) } } }
func TestSchemaMap_Input(t *testing.T) { cases := []struct { Schema map[string]*Schema Config map[string]interface{} Input map[string]string Result map[string]interface{} Err bool }{ /* * String decode */ { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, }, }, Input: map[string]string{ "availability_zone": "foo", }, Result: map[string]interface{}{ "availability_zone": "foo", }, Err: false, }, { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, }, }, Config: map[string]interface{}{ "availability_zone": "bar", }, Input: map[string]string{ "availability_zone": "foo", }, Result: map[string]interface{}{}, Err: false, }, { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Default: "foo", Optional: true, }, }, Input: map[string]string{ "availability_zone": "bar", }, Result: map[string]interface{}{}, Err: false, }, { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, DefaultFunc: func() (interface{}, error) { return "foo", nil }, Optional: true, }, }, Input: map[string]string{ "availability_zone": "bar", }, Result: map[string]interface{}{}, Err: false, }, { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, DefaultFunc: func() (interface{}, error) { return nil, nil }, Optional: true, }, }, Input: map[string]string{ "availability_zone": "bar", }, Result: map[string]interface{}{ "availability_zone": "bar", }, Err: false, }, } for i, tc := range cases { if tc.Config == nil { tc.Config = make(map[string]interface{}) } c, err := config.NewRawConfig(tc.Config) if err != nil { t.Fatalf("err: %s", err) } input := new(terraform.MockUIInput) input.InputReturnMap = tc.Input rc := terraform.NewResourceConfig(c) rc.Config = make(map[string]interface{}) actual, err := schemaMap(tc.Schema).Input(input, rc) if (err != nil) != tc.Err { t.Fatalf("#%d err: %s", i, err) } if !reflect.DeepEqual(tc.Result, actual.Config) { t.Fatalf("#%d: bad:\n\n%#v", i, actual.Config) } } }
func TestSchemaMap_Validate(t *testing.T) { cases := []struct { Schema map[string]*Schema Config map[string]interface{} Vars map[string]string Warn bool Err bool }{ // Good { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, Config: map[string]interface{}{ "availability_zone": "foo", }, }, // Good, because the var is not set and that error will come elsewhere { Schema: map[string]*Schema{ "size": &Schema{ Type: TypeInt, Required: true, }, }, Config: map[string]interface{}{ "size": "${var.foo}", }, Vars: map[string]string{ "var.foo": config.UnknownVariableValue, }, }, // Required field not set { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Required: true, }, }, Config: map[string]interface{}{}, Err: true, }, // Invalid type { Schema: map[string]*Schema{ "port": &Schema{ Type: TypeInt, Required: true, }, }, Config: map[string]interface{}{ "port": "I am invalid", }, Err: true, }, { Schema: map[string]*Schema{ "user_data": &Schema{ Type: TypeString, Optional: true, }, }, Config: map[string]interface{}{ "user_data": []interface{}{ map[string]interface{}{ "foo": "bar", }, }, }, Err: true, }, // Bad type, interpolated { Schema: map[string]*Schema{ "size": &Schema{ Type: TypeInt, Required: true, }, }, Config: map[string]interface{}{ "size": "${var.foo}", }, Vars: map[string]string{ "var.foo": "nope", }, Err: true, }, // Required but has DefaultFunc { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Required: true, DefaultFunc: func() (interface{}, error) { return "foo", nil }, }, }, Config: nil, }, // Required but has DefaultFunc return nil { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Required: true, DefaultFunc: func() (interface{}, error) { return nil, nil }, }, }, Config: nil, Err: true, }, // Optional sub-resource { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, Config: map[string]interface{}{}, Err: false, }, // Not a list { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, Config: map[string]interface{}{ "ingress": "foo", }, Err: true, }, // Required sub-resource field { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, Config: map[string]interface{}{ "ingress": []interface{}{ map[string]interface{}{}, }, }, Err: true, }, // Good sub-resource { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Optional: true, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, Config: map[string]interface{}{ "ingress": []interface{}{ map[string]interface{}{ "from": 80, }, }, }, Err: false, }, // Invalid/unknown field { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, Config: map[string]interface{}{ "foo": "bar", }, Err: true, }, // Computed field set { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Computed: true, }, }, Config: map[string]interface{}{ "availability_zone": "bar", }, Err: true, }, // Not a set { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, Config: map[string]interface{}{ "ports": "foo", }, Err: true, }, // Maps { Schema: map[string]*Schema{ "user_data": &Schema{ Type: TypeMap, Optional: true, }, }, Config: map[string]interface{}{ "user_data": "foo", }, Err: true, }, { Schema: map[string]*Schema{ "user_data": &Schema{ Type: TypeMap, Optional: true, }, }, Config: map[string]interface{}{ "user_data": []interface{}{ map[string]interface{}{ "foo": "bar", }, }, }, }, { Schema: map[string]*Schema{ "user_data": &Schema{ Type: TypeMap, Optional: true, }, }, Config: map[string]interface{}{ "user_data": map[string]interface{}{ "foo": "bar", }, }, }, { Schema: map[string]*Schema{ "user_data": &Schema{ Type: TypeMap, Optional: true, }, }, Config: map[string]interface{}{ "user_data": []interface{}{ "foo", }, }, Err: true, }, } for i, tc := range cases { c, err := config.NewRawConfig(tc.Config) if err != nil { t.Fatalf("err: %s", err) } if tc.Vars != nil { if err := c.Interpolate(tc.Vars); err != nil { t.Fatalf("err: %s", err) } } ws, es := schemaMap(tc.Schema).Validate(terraform.NewResourceConfig(c)) if (len(es) > 0) != tc.Err { if len(es) == 0 { t.Errorf("%d: no errors", i) } for _, e := range es { t.Errorf("%d: err: %s", i, e) } t.FailNow() } if (len(ws) > 0) != tc.Warn { t.Fatalf("%d: ws: %#v", i, ws) } } }
func TestProviderConfigure(t *testing.T) { cases := []struct { P *Provider Config map[string]interface{} Err bool }{ { P: &Provider{}, Config: nil, Err: false, }, { P: &Provider{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, ConfigureFunc: func(d *ResourceData) (interface{}, error) { if d.Get("foo").(int) == 42 { return nil, nil } return nil, fmt.Errorf("nope") }, }, Config: map[string]interface{}{ "foo": 42, }, Err: false, }, { P: &Provider{ Schema: map[string]*Schema{ "foo": &Schema{ Type: TypeInt, Optional: true, }, }, ConfigureFunc: func(d *ResourceData) (interface{}, error) { if d.Get("foo").(int) == 42 { return nil, nil } return nil, fmt.Errorf("nope") }, }, Config: map[string]interface{}{ "foo": 52, }, Err: true, }, } for i, tc := range cases { c, err := config.NewRawConfig(tc.Config) if err != nil { t.Fatalf("err: %s", err) } err = tc.P.Configure(terraform.NewResourceConfig(c)) if err != nil != tc.Err { t.Fatalf("%d: %s", i, err) } } }
func TestSchemaMap_Diff(t *testing.T) { cases := []struct { Schema map[string]*Schema State *terraform.ResourceState Config map[string]interface{} Diff *terraform.ResourceDiff Err bool }{ /* * String decode */ { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{ "availability_zone": "foo", }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", New: "foo", RequiresNew: true, }, }, }, Err: false, }, { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{}, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", NewComputed: true, RequiresNew: true, }, }, }, Err: false, }, { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, State: &terraform.ResourceState{ ID: "foo", }, Config: map[string]interface{}{}, Diff: nil, Err: false, }, // String with StateFunc { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, StateFunc: func(a interface{}) string { return a.(string) + "!" }, }, }, State: nil, Config: map[string]interface{}{ "availability_zone": "foo", }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "", New: "foo!", NewExtra: "foo", }, }, }, Err: false, }, /* * Int decode */ { Schema: map[string]*Schema{ "port": &Schema{ Type: TypeInt, Optional: true, Computed: true, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{ "port": 27, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "port": &terraform.ResourceAttrDiff{ Old: "", New: "27", RequiresNew: true, }, }, }, Err: false, }, /* * Bool decode */ { Schema: map[string]*Schema{ "port": &Schema{ Type: TypeBool, Optional: true, Computed: true, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{ "port": false, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "port": &terraform.ResourceAttrDiff{ Old: "", New: "0", RequiresNew: true, }, }, }, Err: false, }, /* * List decode */ { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{1, 2, 5}, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", New: "3", }, "ports.0": &terraform.ResourceAttrDiff{ Old: "", New: "1", }, "ports.1": &terraform.ResourceAttrDiff{ Old: "", New: "2", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "ports.#": "3", "ports.0": "1", "ports.1": "2", "ports.2": "5", }, }, Config: map[string]interface{}{ "ports": []interface{}{1, 2, 5}, }, Diff: nil, Err: false, }, { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "1", "ports.1": "2", }, }, Config: map[string]interface{}{ "ports": []interface{}{1, 2, 5}, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "2", New: "3", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Required: true, Elem: &Schema{Type: TypeInt}, ForceNew: true, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{1, 2, 5}, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", New: "3", RequiresNew: true, }, "ports.0": &terraform.ResourceAttrDiff{ Old: "", New: "1", RequiresNew: true, }, "ports.1": &terraform.ResourceAttrDiff{ Old: "", New: "2", RequiresNew: true, }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "5", RequiresNew: true, }, }, }, Err: false, }, { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeList, Optional: true, Computed: true, Elem: &Schema{Type: TypeInt}, }, }, State: nil, Config: map[string]interface{}{}, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "", NewComputed: true, }, }, }, Err: false, }, /* * Set */ { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: nil, Config: map[string]interface{}{ "ports": []interface{}{5, 2, 1}, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "0", New: "3", }, "ports.0": &terraform.ResourceAttrDiff{ Old: "", New: "1", }, "ports.1": &terraform.ResourceAttrDiff{ Old: "", New: "2", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "2", "ports.1": "1", }, }, Config: map[string]interface{}{ "ports": []interface{}{5, 2, 1}, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "2", New: "3", }, "ports.2": &terraform.ResourceAttrDiff{ Old: "", New: "5", }, }, }, Err: false, }, { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Required: true, Elem: &Schema{Type: TypeInt}, Set: func(a interface{}) int { return a.(int) }, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "ports.#": "2", "ports.0": "2", "ports.1": "1", }, }, Config: map[string]interface{}{}, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ports.#": &terraform.ResourceAttrDiff{ Old: "2", New: "0", }, "ports.0": &terraform.ResourceAttrDiff{ Old: "1", NewRemoved: true, }, "ports.1": &terraform.ResourceAttrDiff{ Old: "2", NewRemoved: true, }, }, }, Err: false, }, { Schema: map[string]*Schema{ "ports": &Schema{ Type: TypeSet, Optional: true, Computed: true, Elem: &Schema{Type: TypeInt}, Set: func(v interface{}) int { return v.(int) }, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "availability_zone": "bar", "ports.#": "1", "ports.0": "80", }, }, Config: map[string]interface{}{}, Diff: nil, Err: false, }, /* * List of structure decode */ { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Required: true, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, State: nil, Config: map[string]interface{}{ "ingress": []interface{}{ map[string]interface{}{ "from": 8080, }, }, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "ingress.#": &terraform.ResourceAttrDiff{ Old: "0", New: "1", }, "ingress.0.from": &terraform.ResourceAttrDiff{ Old: "", New: "8080", }, }, }, Err: false, }, /* * ComputedWhen */ { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Computed: true, ComputedWhen: []string{"port"}, }, "port": &Schema{ Type: TypeInt, Optional: true, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "availability_zone": "foo", "port": "80", }, }, Config: map[string]interface{}{ "port": 80, }, Diff: nil, Err: false, }, { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Computed: true, ComputedWhen: []string{"port"}, }, "port": &Schema{ Type: TypeInt, Optional: true, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "port": "80", }, }, Config: map[string]interface{}{ "port": 80, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ NewComputed: true, }, }, }, Err: false, }, /* TODO { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Computed: true, ComputedWhen: []string{"port"}, }, "port": &Schema{ Type: TypeInt, Optional: true, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "availability_zone": "foo", "port": "80", }, }, Config: map[string]interface{}{ "port": 8080, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "foo", NewComputed: true, }, "port": &terraform.ResourceAttrDiff{ Old: "80", New: "8080", }, }, }, Err: false, }, */ /* * Maps */ { Schema: map[string]*Schema{ "config_vars": &Schema{ Type: TypeList, Elem: &Schema{Type: TypeMap}, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "config_vars.#": "1", "config_vars.0.foo": "bar", }, }, Config: map[string]interface{}{ "config_vars": []interface{}{ map[string]interface{}{ "bar": "baz", }, }, }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.0.foo": &terraform.ResourceAttrDiff{ Old: "bar", NewRemoved: true, }, "config_vars.0.bar": &terraform.ResourceAttrDiff{ Old: "", New: "baz", }, }, }, Err: false, }, { Schema: map[string]*Schema{ "config_vars": &Schema{ Type: TypeList, Elem: &Schema{Type: TypeMap}, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "config_vars.#": "1", "config_vars.0.foo": "bar", "config_vars.0.bar": "baz", }, }, Config: map[string]interface{}{}, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "config_vars.#": &terraform.ResourceAttrDiff{ Old: "1", New: "0", }, "config_vars.0.foo": &terraform.ResourceAttrDiff{ Old: "bar", NewRemoved: true, }, "config_vars.0.bar": &terraform.ResourceAttrDiff{ Old: "baz", NewRemoved: true, }, }, }, Err: false, }, /* * ForceNews */ { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, ForceNew: true, }, "address": &Schema{ Type: TypeString, Optional: true, Computed: true, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "availability_zone": "bar", "address": "foo", }, }, Config: map[string]interface{}{ "availability_zone": "foo", }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "bar", New: "foo", RequiresNew: true, }, "address": &terraform.ResourceAttrDiff{ Old: "foo", New: "", NewComputed: true, }, }, }, Err: false, }, // Set { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, ForceNew: true, }, "ports": &Schema{ Type: TypeSet, Optional: true, Computed: true, Elem: &Schema{Type: TypeInt}, Set: func(v interface{}) int { return v.(int) }, }, }, State: &terraform.ResourceState{ Attributes: map[string]string{ "availability_zone": "bar", "ports.#": "1", "ports.0": "80", }, }, Config: map[string]interface{}{ "availability_zone": "foo", }, Diff: &terraform.ResourceDiff{ Attributes: map[string]*terraform.ResourceAttrDiff{ "availability_zone": &terraform.ResourceAttrDiff{ Old: "bar", New: "foo", RequiresNew: true, }, "ports.#": &terraform.ResourceAttrDiff{ Old: "1", New: "", NewComputed: true, }, }, }, Err: false, }, } for i, tc := range cases { c, err := config.NewRawConfig(tc.Config) if err != nil { t.Fatalf("err: %s", err) } d, err := schemaMap(tc.Schema).Diff( tc.State, terraform.NewResourceConfig(c)) if (err != nil) != tc.Err { t.Fatalf("#%d err: %s", i, err) } if !reflect.DeepEqual(tc.Diff, d) { t.Fatalf("#%d: bad:\n\n%#v", i, d) } } }
func TestSchemaMap_Validate(t *testing.T) { cases := []struct { Schema map[string]*Schema Config map[string]interface{} Warn bool Err bool }{ // Good { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, Config: map[string]interface{}{ "availability_zone": "foo", }, }, // Required field not set { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Required: true, }, }, Config: map[string]interface{}{}, Err: true, }, // Invalid type { Schema: map[string]*Schema{ "port": &Schema{ Type: TypeInt, Required: true, }, }, Config: map[string]interface{}{ "port": "I am invalid", }, Err: true, }, // Optional sub-resource { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, Config: map[string]interface{}{}, Err: false, }, // Not a list { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, Config: map[string]interface{}{ "ingress": "foo", }, Err: true, }, // Required sub-resource field { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, Config: map[string]interface{}{ "ingress": []interface{}{ map[string]interface{}{}, }, }, Err: true, }, // Good sub-resource { Schema: map[string]*Schema{ "ingress": &Schema{ Type: TypeList, Optional: true, Elem: &Resource{ Schema: map[string]*Schema{ "from": &Schema{ Type: TypeInt, Required: true, }, }, }, }, }, Config: map[string]interface{}{ "ingress": []interface{}{ map[string]interface{}{ "from": 80, }, }, }, Err: false, }, // Invalid/unknown field { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Optional: true, Computed: true, ForceNew: true, }, }, Config: map[string]interface{}{ "foo": "bar", }, Err: true, }, // Computed field set { Schema: map[string]*Schema{ "availability_zone": &Schema{ Type: TypeString, Computed: true, }, }, Config: map[string]interface{}{ "availability_zone": "bar", }, Err: true, }, } for i, tc := range cases { c, err := config.NewRawConfig(tc.Config) if err != nil { t.Fatalf("err: %s", err) } ws, es := schemaMap(tc.Schema).Validate(terraform.NewResourceConfig(c)) if (len(es) > 0) != tc.Err { if len(es) == 0 { t.Errorf("%d: no errors", i) } for _, e := range es { t.Errorf("%d: err: %s", i, e) } t.FailNow() } if (len(ws) > 0) != tc.Warn { t.Fatalf("%d: ws: %#v", i, ws) } } }