696 lines
14 KiB
Go
696 lines
14 KiB
Go
package schema
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/hil/ast"
|
|
"github.com/hashicorp/terraform/config"
|
|
"github.com/hashicorp/terraform/helper/hashcode"
|
|
"github.com/hashicorp/terraform/terraform"
|
|
)
|
|
|
|
func TestConfigFieldReader_impl(t *testing.T) {
|
|
var _ FieldReader = new(ConfigFieldReader)
|
|
}
|
|
|
|
func TestConfigFieldReader(t *testing.T) {
|
|
testFieldReader(t, func(s map[string]*Schema) FieldReader {
|
|
return &ConfigFieldReader{
|
|
Schema: s,
|
|
|
|
Config: testConfig(t, map[string]interface{}{
|
|
"bool": true,
|
|
"float": 3.1415,
|
|
"int": 42,
|
|
"string": "string",
|
|
|
|
"list": []interface{}{"foo", "bar"},
|
|
|
|
"listInt": []interface{}{21, 42},
|
|
|
|
"map": map[string]interface{}{
|
|
"foo": "bar",
|
|
"bar": "baz",
|
|
},
|
|
"mapInt": map[string]interface{}{
|
|
"one": "1",
|
|
"two": "2",
|
|
},
|
|
"mapFloat": map[string]interface{}{
|
|
"oneDotTwo": "1.2",
|
|
},
|
|
"mapBool": map[string]interface{}{
|
|
"True": "true",
|
|
"False": "false",
|
|
},
|
|
|
|
"set": []interface{}{10, 50},
|
|
"setDeep": []interface{}{
|
|
map[string]interface{}{
|
|
"index": 10,
|
|
"value": "foo",
|
|
},
|
|
map[string]interface{}{
|
|
"index": 50,
|
|
"value": "bar",
|
|
},
|
|
},
|
|
}),
|
|
}
|
|
})
|
|
}
|
|
|
|
// This contains custom table tests for our ConfigFieldReader
|
|
func TestConfigFieldReader_custom(t *testing.T) {
|
|
schema := map[string]*Schema{
|
|
"bool": &Schema{
|
|
Type: TypeBool,
|
|
},
|
|
}
|
|
|
|
cases := map[string]struct {
|
|
Addr []string
|
|
Result FieldReadResult
|
|
Config *terraform.ResourceConfig
|
|
Err bool
|
|
}{
|
|
"basic": {
|
|
[]string{"bool"},
|
|
FieldReadResult{
|
|
Value: true,
|
|
Exists: true,
|
|
},
|
|
testConfig(t, map[string]interface{}{
|
|
"bool": true,
|
|
}),
|
|
false,
|
|
},
|
|
|
|
"computed": {
|
|
[]string{"bool"},
|
|
FieldReadResult{
|
|
Exists: true,
|
|
Computed: true,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"bool": "${var.foo}",
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Value: config.UnknownVariableValue,
|
|
Type: ast.TypeString,
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for name, tc := range cases {
|
|
t.Run(name, func(t *testing.T) {
|
|
r := &ConfigFieldReader{
|
|
Schema: schema,
|
|
Config: tc.Config,
|
|
}
|
|
out, err := r.ReadField(tc.Addr)
|
|
if err != nil != tc.Err {
|
|
t.Fatalf("%s: err: %s", name, err)
|
|
}
|
|
if s, ok := out.Value.(*Set); ok {
|
|
// If it is a set, convert to a list so its more easily checked.
|
|
out.Value = s.List()
|
|
}
|
|
if !reflect.DeepEqual(tc.Result, out) {
|
|
t.Fatalf("%s: bad: %#v", name, out)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfigFieldReader_DefaultHandling(t *testing.T) {
|
|
schema := map[string]*Schema{
|
|
"strWithDefault": &Schema{
|
|
Type: TypeString,
|
|
Default: "ImADefault",
|
|
},
|
|
"strWithDefaultFunc": &Schema{
|
|
Type: TypeString,
|
|
DefaultFunc: func() (interface{}, error) {
|
|
return "FuncDefault", nil
|
|
},
|
|
},
|
|
}
|
|
|
|
cases := map[string]struct {
|
|
Addr []string
|
|
Result FieldReadResult
|
|
Config *terraform.ResourceConfig
|
|
Err bool
|
|
}{
|
|
"gets default value when no config set": {
|
|
[]string{"strWithDefault"},
|
|
FieldReadResult{
|
|
Value: "ImADefault",
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfig(t, map[string]interface{}{}),
|
|
false,
|
|
},
|
|
"config overrides default value": {
|
|
[]string{"strWithDefault"},
|
|
FieldReadResult{
|
|
Value: "fromConfig",
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfig(t, map[string]interface{}{
|
|
"strWithDefault": "fromConfig",
|
|
}),
|
|
false,
|
|
},
|
|
"gets default from function when no config set": {
|
|
[]string{"strWithDefaultFunc"},
|
|
FieldReadResult{
|
|
Value: "FuncDefault",
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfig(t, map[string]interface{}{}),
|
|
false,
|
|
},
|
|
"config overrides default function": {
|
|
[]string{"strWithDefaultFunc"},
|
|
FieldReadResult{
|
|
Value: "fromConfig",
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfig(t, map[string]interface{}{
|
|
"strWithDefaultFunc": "fromConfig",
|
|
}),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for name, tc := range cases {
|
|
r := &ConfigFieldReader{
|
|
Schema: schema,
|
|
Config: tc.Config,
|
|
}
|
|
out, err := r.ReadField(tc.Addr)
|
|
if err != nil != tc.Err {
|
|
t.Fatalf("%s: err: %s", name, err)
|
|
}
|
|
if s, ok := out.Value.(*Set); ok {
|
|
// If it is a set, convert to a list so its more easily checked.
|
|
out.Value = s.List()
|
|
}
|
|
if !reflect.DeepEqual(tc.Result, out) {
|
|
t.Fatalf("%s: bad: %#v", name, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConfigFieldReader_ComputedMap(t *testing.T) {
|
|
schema := map[string]*Schema{
|
|
"map": &Schema{
|
|
Type: TypeMap,
|
|
Computed: true,
|
|
},
|
|
"listmap": &Schema{
|
|
Type: TypeMap,
|
|
Computed: true,
|
|
Elem: TypeList,
|
|
},
|
|
"maplist": &Schema{
|
|
Type: TypeList,
|
|
Computed: true,
|
|
Elem: TypeMap,
|
|
},
|
|
}
|
|
|
|
cases := []struct {
|
|
Name string
|
|
Addr []string
|
|
Result FieldReadResult
|
|
Config *terraform.ResourceConfig
|
|
Err bool
|
|
}{
|
|
{
|
|
"set, normal",
|
|
[]string{"map"},
|
|
FieldReadResult{
|
|
Value: map[string]interface{}{
|
|
"foo": "bar",
|
|
},
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfig(t, map[string]interface{}{
|
|
"map": map[string]interface{}{
|
|
"foo": "bar",
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
{
|
|
"computed element",
|
|
[]string{"map"},
|
|
FieldReadResult{
|
|
Exists: true,
|
|
Computed: true,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"map": map[string]interface{}{
|
|
"foo": "${var.foo}",
|
|
},
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Value: config.UnknownVariableValue,
|
|
Type: ast.TypeString,
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
{
|
|
"native map",
|
|
[]string{"map"},
|
|
FieldReadResult{
|
|
Value: map[string]interface{}{
|
|
"bar": "baz",
|
|
"baz": "bar",
|
|
},
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"map": "${var.foo}",
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Type: ast.TypeMap,
|
|
Value: map[string]ast.Variable{
|
|
"bar": ast.Variable{
|
|
Type: ast.TypeString,
|
|
Value: "baz",
|
|
},
|
|
"baz": ast.Variable{
|
|
Type: ast.TypeString,
|
|
Value: "bar",
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
{
|
|
"map-from-list-of-maps",
|
|
[]string{"maplist", "0"},
|
|
FieldReadResult{
|
|
Value: map[string]interface{}{
|
|
"key": "bar",
|
|
},
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"maplist": "${var.foo}",
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Type: ast.TypeList,
|
|
Value: []ast.Variable{
|
|
{
|
|
Type: ast.TypeMap,
|
|
Value: map[string]ast.Variable{
|
|
"key": ast.Variable{
|
|
Type: ast.TypeString,
|
|
Value: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
{
|
|
"value-from-list-of-maps",
|
|
[]string{"maplist", "0", "key"},
|
|
FieldReadResult{
|
|
Value: "bar",
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"maplist": "${var.foo}",
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Type: ast.TypeList,
|
|
Value: []ast.Variable{
|
|
{
|
|
Type: ast.TypeMap,
|
|
Value: map[string]ast.Variable{
|
|
"key": ast.Variable{
|
|
Type: ast.TypeString,
|
|
Value: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
{
|
|
"list-from-map-of-lists",
|
|
[]string{"listmap", "key"},
|
|
FieldReadResult{
|
|
Value: []interface{}{"bar"},
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"listmap": "${var.foo}",
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Type: ast.TypeMap,
|
|
Value: map[string]ast.Variable{
|
|
"key": ast.Variable{
|
|
Type: ast.TypeList,
|
|
Value: []ast.Variable{
|
|
ast.Variable{
|
|
Type: ast.TypeString,
|
|
Value: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
{
|
|
"value-from-map-of-lists",
|
|
[]string{"listmap", "key", "0"},
|
|
FieldReadResult{
|
|
Value: "bar",
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"listmap": "${var.foo}",
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Type: ast.TypeMap,
|
|
Value: map[string]ast.Variable{
|
|
"key": ast.Variable{
|
|
Type: ast.TypeList,
|
|
Value: []ast.Variable{
|
|
ast.Variable{
|
|
Type: ast.TypeString,
|
|
Value: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for i, tc := range cases {
|
|
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
|
|
r := &ConfigFieldReader{
|
|
Schema: schema,
|
|
Config: tc.Config,
|
|
}
|
|
out, err := r.ReadField(tc.Addr)
|
|
if err != nil != tc.Err {
|
|
t.Fatal(err)
|
|
}
|
|
if s, ok := out.Value.(*Set); ok {
|
|
// If it is a set, convert to the raw map
|
|
out.Value = s.m
|
|
if len(s.m) == 0 {
|
|
out.Value = nil
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(tc.Result, out) {
|
|
t.Fatalf("\nexpected: %#v\ngot: %#v", tc.Result, out)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfigFieldReader_ComputedSet(t *testing.T) {
|
|
schema := map[string]*Schema{
|
|
"strSet": &Schema{
|
|
Type: TypeSet,
|
|
Elem: &Schema{Type: TypeString},
|
|
Set: HashString,
|
|
},
|
|
}
|
|
|
|
cases := map[string]struct {
|
|
Addr []string
|
|
Result FieldReadResult
|
|
Config *terraform.ResourceConfig
|
|
Err bool
|
|
}{
|
|
"set, normal": {
|
|
[]string{"strSet"},
|
|
FieldReadResult{
|
|
Value: map[string]interface{}{
|
|
"2356372769": "foo",
|
|
},
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfig(t, map[string]interface{}{
|
|
"strSet": []interface{}{"foo"},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
"set, computed element": {
|
|
[]string{"strSet"},
|
|
FieldReadResult{
|
|
Value: nil,
|
|
Exists: true,
|
|
Computed: true,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"strSet": []interface{}{"${var.foo}"},
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Value: config.UnknownVariableValue,
|
|
Type: ast.TypeUnknown,
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
"set, computed element substring": {
|
|
[]string{"strSet"},
|
|
FieldReadResult{
|
|
Value: nil,
|
|
Exists: true,
|
|
Computed: true,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"strSet": []interface{}{"${var.foo}/32"},
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Value: config.UnknownVariableValue,
|
|
Type: ast.TypeUnknown,
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for name, tc := range cases {
|
|
r := &ConfigFieldReader{
|
|
Schema: schema,
|
|
Config: tc.Config,
|
|
}
|
|
out, err := r.ReadField(tc.Addr)
|
|
if err != nil != tc.Err {
|
|
t.Fatalf("%s: err: %s", name, err)
|
|
}
|
|
if s, ok := out.Value.(*Set); ok {
|
|
// If it is a set, convert to the raw map
|
|
out.Value = s.m
|
|
if len(s.m) == 0 {
|
|
out.Value = nil
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(tc.Result, out) {
|
|
t.Fatalf("%s: bad: %#v", name, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConfigFieldReader_computedComplexSet(t *testing.T) {
|
|
hashfunc := func(v interface{}) int {
|
|
var buf bytes.Buffer
|
|
m := v.(map[string]interface{})
|
|
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
|
|
buf.WriteString(fmt.Sprintf("%s-", m["vhd_uri"].(string)))
|
|
return hashcode.String(buf.String())
|
|
}
|
|
|
|
schema := map[string]*Schema{
|
|
"set": &Schema{
|
|
Type: TypeSet,
|
|
Elem: &Resource{
|
|
Schema: map[string]*Schema{
|
|
"name": {
|
|
Type: TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"vhd_uri": {
|
|
Type: TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Set: hashfunc,
|
|
},
|
|
}
|
|
|
|
cases := map[string]struct {
|
|
Addr []string
|
|
Result FieldReadResult
|
|
Config *terraform.ResourceConfig
|
|
Err bool
|
|
}{
|
|
"set, normal": {
|
|
[]string{"set"},
|
|
FieldReadResult{
|
|
Value: map[string]interface{}{
|
|
"532860136": map[string]interface{}{
|
|
"name": "myosdisk1",
|
|
"vhd_uri": "bar",
|
|
},
|
|
},
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfig(t, map[string]interface{}{
|
|
"set": []interface{}{
|
|
map[string]interface{}{
|
|
"name": "myosdisk1",
|
|
"vhd_uri": "bar",
|
|
},
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
"set, computed element": {
|
|
[]string{"set"},
|
|
FieldReadResult{
|
|
Value: map[string]interface{}{
|
|
"~3596295623": map[string]interface{}{
|
|
"name": "myosdisk1",
|
|
"vhd_uri": "${var.foo}/bar",
|
|
},
|
|
},
|
|
Exists: true,
|
|
Computed: false,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"set": []interface{}{
|
|
map[string]interface{}{
|
|
"name": "myosdisk1",
|
|
"vhd_uri": "${var.foo}/bar",
|
|
},
|
|
},
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Value: config.UnknownVariableValue,
|
|
Type: ast.TypeUnknown,
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
|
|
"set, computed element single": {
|
|
[]string{"set", "~3596295623", "vhd_uri"},
|
|
FieldReadResult{
|
|
Value: "${var.foo}/bar",
|
|
Exists: true,
|
|
Computed: true,
|
|
},
|
|
testConfigInterpolate(t, map[string]interface{}{
|
|
"set": []interface{}{
|
|
map[string]interface{}{
|
|
"name": "myosdisk1",
|
|
"vhd_uri": "${var.foo}/bar",
|
|
},
|
|
},
|
|
}, map[string]ast.Variable{
|
|
"var.foo": ast.Variable{
|
|
Value: config.UnknownVariableValue,
|
|
Type: ast.TypeUnknown,
|
|
},
|
|
}),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for name, tc := range cases {
|
|
r := &ConfigFieldReader{
|
|
Schema: schema,
|
|
Config: tc.Config,
|
|
}
|
|
out, err := r.ReadField(tc.Addr)
|
|
if err != nil != tc.Err {
|
|
t.Fatalf("%s: err: %s", name, err)
|
|
}
|
|
if s, ok := out.Value.(*Set); ok {
|
|
// If it is a set, convert to the raw map
|
|
out.Value = s.m
|
|
if len(s.m) == 0 {
|
|
out.Value = nil
|
|
}
|
|
}
|
|
if !reflect.DeepEqual(tc.Result, out) {
|
|
t.Fatalf("%s: bad: %#v", name, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testConfig(
|
|
t *testing.T, raw map[string]interface{}) *terraform.ResourceConfig {
|
|
return testConfigInterpolate(t, raw, nil)
|
|
}
|
|
|
|
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)
|
|
}
|