helper/schema: field readers no longer take a schema as arg

This commit is contained in:
Mitchell Hashimoto 2015-01-03 12:13:46 -05:00
parent 3ff859d734
commit 7e379cb1a1
10 changed files with 370 additions and 249 deletions

View File

@ -9,7 +9,7 @@ import (
// the proper typed representation. ResourceData uses this to query data
// out of multiple sources: config, state, diffs, etc.
type FieldReader interface {
ReadField([]string, *Schema) (FieldReadResult, error)
ReadField([]string) (FieldReadResult, error)
}
// FieldReadResult encapsulates all the resulting data from reading
@ -31,14 +31,92 @@ type FieldReadResult struct {
Computed bool
}
// addrToSchema finds the final element schema for the given address
// and the given schema.
func addrToSchema(addr []string, schemaMap map[string]*Schema) *Schema {
var result *Schema
var lastType ValueType
current := &Schema{
Type: typeObject,
Elem: schemaMap,
}
for len(addr) > 0 {
k := addr[0]
addr = addr[1:]
REPEAT:
if len(addr) == 0 {
result = current
}
currentType := current.Type
switch current.Type {
case TypeBool:
fallthrough
case TypeInt:
fallthrough
case TypeString:
if len(addr) > 0 {
return nil
}
case TypeList:
fallthrough
case TypeSet:
switch v := current.Elem.(type) {
case *Resource:
current = &Schema{
Type: typeObject,
Elem: v.Schema,
}
case *Schema:
current = v
default:
return nil
}
if len(addr) > 0 && addr[0] == "#" {
current = &Schema{Type: TypeInt}
}
case TypeMap:
if len(addr) > 0 {
current = &Schema{Type: TypeString}
}
case typeObject:
if lastType == TypeSet || lastType == TypeList {
// We just ignore sets/lists since they don't access
// objects the same way.
break
}
m := current.Elem.(map[string]*Schema)
val, ok := m[k]
if !ok {
return nil
}
current = val
goto REPEAT
}
lastType = currentType
}
return result
}
// readListField is a generic method for reading a list field out of a
// a FieldReader. It does this based on the assumption that there is a key
// "foo.#" for a list "foo" and that the indexes are "foo.0", "foo.1", etc.
// after that point.
func readListField(
r FieldReader, k string, schema *Schema) (FieldReadResult, error) {
r FieldReader, addr []string, schema *Schema) (FieldReadResult, error) {
addrPadded := make([]string, len(addr)+1)
copy(addrPadded, addr)
addrPadded[len(addrPadded)-1] = "#"
// Get the number of elements in the list
countResult, err := r.ReadField([]string{k + ".#"}, &Schema{Type: TypeInt})
countResult, err := r.ReadField(addrPadded)
if err != nil {
return FieldReadResult{}, err
}
@ -56,23 +134,12 @@ func readListField(
}, nil
}
// Get the schema for the elements
var elemSchema *Schema
switch t := schema.Elem.(type) {
case *Resource:
elemSchema = &Schema{
Type: typeObject,
Elem: t.Schema,
}
case *Schema:
elemSchema = t
}
// Go through each count, and get the item value out of it
result := make([]interface{}, countResult.Value.(int))
for i, _ := range result {
is := strconv.FormatInt(int64(i), 10)
rawResult, err := r.ReadField([]string{k, is}, elemSchema)
addrPadded[len(addrPadded)-1] = is
rawResult, err := r.ReadField(addrPadded)
if err != nil {
return FieldReadResult{}, err
}
@ -97,11 +164,14 @@ func readListField(
// will result in the proper field data.
func readObjectField(
r FieldReader,
k string,
addr []string,
schema map[string]*Schema) (FieldReadResult, error) {
result := make(map[string]interface{})
for field, schema := range schema {
rawResult, err := r.ReadField([]string{k, field}, schema)
for field, _ := range schema {
addrRead := make([]string, len(addr), len(addr)+1)
copy(addrRead, addr)
addrRead = append(addrRead, field)
rawResult, err := r.ReadField(addrRead)
if err != nil {
return FieldReadResult{}, err
}

View File

@ -12,11 +12,15 @@ import (
// the best of its ability.
type ConfigFieldReader struct {
Config *terraform.ResourceConfig
Schema map[string]*Schema
}
func (r *ConfigFieldReader) ReadField(
address []string, schema *Schema) (FieldReadResult, error) {
func (r *ConfigFieldReader) ReadField(address []string) (FieldReadResult, error) {
k := strings.Join(address, ".")
schema := addrToSchema(address, r.Schema)
if schema == nil {
return FieldReadResult{}, nil
}
switch schema.Type {
case TypeBool:
@ -26,13 +30,13 @@ func (r *ConfigFieldReader) ReadField(
case TypeString:
return r.readPrimitive(k, schema)
case TypeList:
return readListField(r, k, schema)
return readListField(r, address, schema)
case TypeMap:
return r.readMap(k)
case TypeSet:
return r.readSet(k, schema)
return r.readSet(address, schema)
case typeObject:
return readObjectField(r, k, schema.Elem.(map[string]*Schema))
return readObjectField(r, address, schema.Elem.(map[string]*Schema))
default:
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
}
@ -96,8 +100,8 @@ func (r *ConfigFieldReader) readPrimitive(
}
func (r *ConfigFieldReader) readSet(
k string, schema *Schema) (FieldReadResult, error) {
raw, err := readListField(r, k, schema)
address []string, schema *Schema) (FieldReadResult, error) {
raw, err := readListField(r, address, schema)
if err != nil {
return FieldReadResult{}, err
}

View File

@ -14,6 +14,40 @@ func TestConfigFieldReader_impl(t *testing.T) {
func TestConfigFieldReader(t *testing.T) {
r := &ConfigFieldReader{
Schema: map[string]*Schema{
"bool": &Schema{Type: TypeBool},
"int": &Schema{Type: TypeInt},
"string": &Schema{Type: TypeString},
"list": &Schema{
Type: TypeList,
Elem: &Schema{Type: TypeString},
},
"listInt": &Schema{
Type: TypeList,
Elem: &Schema{Type: TypeInt},
},
"map": &Schema{Type: TypeMap},
"set": &Schema{
Type: TypeSet,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int {
return a.(int)
},
},
"setDeep": &Schema{
Type: TypeSet,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{Type: TypeInt},
"value": &Schema{Type: TypeString},
},
},
Set: func(a interface{}) int {
return a.(map[string]interface{})["index"].(int)
},
},
},
Config: testConfig(t, map[string]interface{}{
"bool": true,
"int": 42,
@ -45,7 +79,6 @@ func TestConfigFieldReader(t *testing.T) {
cases := map[string]struct {
Addr []string
Schema *Schema
Out interface{}
OutOk bool
OutComputed bool
@ -53,7 +86,6 @@ func TestConfigFieldReader(t *testing.T) {
}{
"noexist": {
[]string{"boolNOPE"},
&Schema{Type: TypeBool},
nil,
false,
false,
@ -62,7 +94,6 @@ func TestConfigFieldReader(t *testing.T) {
"bool": {
[]string{"bool"},
&Schema{Type: TypeBool},
true,
true,
false,
@ -71,7 +102,6 @@ func TestConfigFieldReader(t *testing.T) {
"int": {
[]string{"int"},
&Schema{Type: TypeInt},
42,
true,
false,
@ -80,7 +110,6 @@ func TestConfigFieldReader(t *testing.T) {
"string": {
[]string{"string"},
&Schema{Type: TypeString},
"string",
true,
false,
@ -89,10 +118,6 @@ func TestConfigFieldReader(t *testing.T) {
"list": {
[]string{"list"},
&Schema{
Type: TypeList,
Elem: &Schema{Type: TypeString},
},
[]interface{}{
"foo",
"bar",
@ -104,10 +129,6 @@ func TestConfigFieldReader(t *testing.T) {
"listInt": {
[]string{"listInt"},
&Schema{
Type: TypeList,
Elem: &Schema{Type: TypeInt},
},
[]interface{}{
21,
42,
@ -119,7 +140,6 @@ func TestConfigFieldReader(t *testing.T) {
"map": {
[]string{"map"},
&Schema{Type: TypeMap},
map[string]interface{}{
"foo": "bar",
"bar": "baz",
@ -131,7 +151,6 @@ func TestConfigFieldReader(t *testing.T) {
"mapelem": {
[]string{"map", "foo"},
&Schema{Type: TypeString},
"bar",
true,
false,
@ -140,13 +159,6 @@ func TestConfigFieldReader(t *testing.T) {
"set": {
[]string{"set"},
&Schema{
Type: TypeSet,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int {
return a.(int)
},
},
[]interface{}{10, 50},
true,
false,
@ -155,18 +167,6 @@ func TestConfigFieldReader(t *testing.T) {
"setDeep": {
[]string{"setDeep"},
&Schema{
Type: TypeSet,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{Type: TypeInt},
"value": &Schema{Type: TypeString},
},
},
Set: func(a interface{}) int {
return a.(map[string]interface{})["index"].(int)
},
},
[]interface{}{
map[string]interface{}{
"index": 10,
@ -184,7 +184,7 @@ func TestConfigFieldReader(t *testing.T) {
}
for name, tc := range cases {
out, err := r.ReadField(tc.Addr, tc.Schema)
out, err := r.ReadField(tc.Addr)
if (err != nil) != tc.OutErr {
t.Fatalf("%s: err: %s", name, err)
}

View File

@ -28,11 +28,14 @@ import (
type DiffFieldReader struct {
Diff *terraform.InstanceDiff
Source FieldReader
Schema map[string]*Schema
}
func (r *DiffFieldReader) ReadField(
address []string, schema *Schema) (FieldReadResult, error) {
k := strings.Join(address, ".")
func (r *DiffFieldReader) ReadField(address []string) (FieldReadResult, error) {
schema := addrToSchema(address, r.Schema)
if schema == nil {
return FieldReadResult{}, nil
}
switch schema.Type {
case TypeBool:
@ -40,27 +43,27 @@ func (r *DiffFieldReader) ReadField(
case TypeInt:
fallthrough
case TypeString:
return r.readPrimitive(k, schema)
return r.readPrimitive(address, schema)
case TypeList:
return readListField(r, k, schema)
return readListField(r, address, schema)
case TypeMap:
return r.readMap(k, schema)
return r.readMap(address, schema)
case TypeSet:
return r.readSet(k, schema)
return r.readSet(address, schema)
case typeObject:
return readObjectField(r, k, schema.Elem.(map[string]*Schema))
return readObjectField(r, address, schema.Elem.(map[string]*Schema))
default:
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
}
}
func (r *DiffFieldReader) readMap(
k string, schema *Schema) (FieldReadResult, error) {
address []string, schema *Schema) (FieldReadResult, error) {
result := make(map[string]interface{})
resultSet := false
// First read the map from the underlying source
source, err := r.Source.ReadField([]string{k}, schema)
source, err := r.Source.ReadField(address)
if err != nil {
return FieldReadResult{}, err
}
@ -71,7 +74,7 @@ func (r *DiffFieldReader) readMap(
// Next, read all the elements we have in our diff, and apply
// the diff to our result.
prefix := k + "."
prefix := strings.Join(address, ".") + "."
for k, v := range r.Diff.Attributes {
if !strings.HasPrefix(k, prefix) {
continue
@ -99,13 +102,13 @@ func (r *DiffFieldReader) readMap(
}
func (r *DiffFieldReader) readPrimitive(
k string, schema *Schema) (FieldReadResult, error) {
result, err := r.Source.ReadField([]string{k}, schema)
address []string, schema *Schema) (FieldReadResult, error) {
result, err := r.Source.ReadField(address)
if err != nil {
return FieldReadResult{}, err
}
attrD, ok := r.Diff.Attributes[k]
attrD, ok := r.Diff.Attributes[strings.Join(address, ".")]
if !ok {
return result, nil
}
@ -131,24 +134,12 @@ func (r *DiffFieldReader) readPrimitive(
}
func (r *DiffFieldReader) readSet(
k string, schema *Schema) (FieldReadResult, error) {
address []string, schema *Schema) (FieldReadResult, error) {
// Create the set that will be our result
set := &Set{F: schema.Set}
// Get the schema for the elements
var elemSchema *Schema
switch t := schema.Elem.(type) {
case *Resource:
elemSchema = &Schema{
Type: typeObject,
Elem: t.Schema,
}
case *Schema:
elemSchema = t
}
// Go through the map and find all the set items
prefix := k + "."
prefix := strings.Join(address, ".") + "."
for k, _ := range r.Diff.Attributes {
if !strings.HasPrefix(k, prefix) {
continue
@ -162,7 +153,7 @@ func (r *DiffFieldReader) readSet(
parts := strings.Split(k[len(prefix):], ".")
idx := parts[0]
raw, err := r.ReadField([]string{prefix + idx}, elemSchema)
raw, err := r.ReadField(append(address, idx))
if err != nil {
return FieldReadResult{}, err
}

View File

@ -12,7 +12,71 @@ func TestDiffFieldReader_impl(t *testing.T) {
}
func TestDiffFieldReader(t *testing.T) {
schema := map[string]*Schema{
"bool": &Schema{Type: TypeBool},
"int": &Schema{Type: TypeInt},
"string": &Schema{Type: TypeString},
"stringComputed": &Schema{Type: TypeString},
"list": &Schema{
Type: TypeList,
Elem: &Schema{Type: TypeString},
},
"listInt": &Schema{
Type: TypeList,
Elem: &Schema{Type: TypeInt},
},
"listMap": &Schema{
Type: TypeList,
Elem: &Schema{
Type: TypeMap,
},
},
"map": &Schema{Type: TypeMap},
"mapRemove": &Schema{Type: TypeMap},
"set": &Schema{
Type: TypeSet,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int {
return a.(int)
},
},
"setChange": &Schema{
Type: TypeSet,
Optional: true,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{
Type: TypeInt,
Required: true,
},
"value": &Schema{
Type: TypeString,
Required: true,
},
},
},
Set: func(a interface{}) int {
m := a.(map[string]interface{})
return m["index"].(int)
},
},
"setDeep": &Schema{
Type: TypeSet,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{Type: TypeInt},
"value": &Schema{Type: TypeString},
},
},
Set: func(a interface{}) int {
return a.(map[string]interface{})["index"].(int)
},
},
}
r := &DiffFieldReader{
Schema: schema,
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"bool": &terraform.ResourceAttrDiff{
@ -132,6 +196,7 @@ func TestDiffFieldReader(t *testing.T) {
},
Source: &MapFieldReader{
Schema: schema,
Map: map[string]string{
"listMap.#": "2",
"listMap.0.foo": "bar",
@ -150,13 +215,11 @@ func TestDiffFieldReader(t *testing.T) {
cases := map[string]struct {
Addr []string
Schema *Schema
Result FieldReadResult
Err bool
}{
"noexist": {
[]string{"boolNOPE"},
&Schema{Type: TypeBool},
FieldReadResult{
Value: nil,
Exists: false,
@ -167,7 +230,6 @@ func TestDiffFieldReader(t *testing.T) {
"bool": {
[]string{"bool"},
&Schema{Type: TypeBool},
FieldReadResult{
Value: true,
Exists: true,
@ -178,7 +240,6 @@ func TestDiffFieldReader(t *testing.T) {
"int": {
[]string{"int"},
&Schema{Type: TypeInt},
FieldReadResult{
Value: 42,
Exists: true,
@ -189,7 +250,6 @@ func TestDiffFieldReader(t *testing.T) {
"string": {
[]string{"string"},
&Schema{Type: TypeString},
FieldReadResult{
Value: "string",
Exists: true,
@ -200,7 +260,6 @@ func TestDiffFieldReader(t *testing.T) {
"stringComputed": {
[]string{"stringComputed"},
&Schema{Type: TypeString},
FieldReadResult{
Value: "",
Exists: true,
@ -211,10 +270,6 @@ func TestDiffFieldReader(t *testing.T) {
"list": {
[]string{"list"},
&Schema{
Type: TypeList,
Elem: &Schema{Type: TypeString},
},
FieldReadResult{
Value: []interface{}{
"foo",
@ -228,10 +283,6 @@ func TestDiffFieldReader(t *testing.T) {
"listInt": {
[]string{"listInt"},
&Schema{
Type: TypeList,
Elem: &Schema{Type: TypeInt},
},
FieldReadResult{
Value: []interface{}{
21,
@ -245,7 +296,6 @@ func TestDiffFieldReader(t *testing.T) {
"map": {
[]string{"map"},
&Schema{Type: TypeMap},
FieldReadResult{
Value: map[string]interface{}{
"foo": "bar",
@ -259,7 +309,6 @@ func TestDiffFieldReader(t *testing.T) {
"mapelem": {
[]string{"map", "foo"},
&Schema{Type: TypeString},
FieldReadResult{
Value: "bar",
Exists: true,
@ -270,7 +319,6 @@ func TestDiffFieldReader(t *testing.T) {
"mapRemove": {
[]string{"mapRemove"},
&Schema{Type: TypeMap},
FieldReadResult{
Value: map[string]interface{}{
"foo": "bar",
@ -283,13 +331,6 @@ func TestDiffFieldReader(t *testing.T) {
"set": {
[]string{"set"},
&Schema{
Type: TypeSet,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int {
return a.(int)
},
},
FieldReadResult{
Value: []interface{}{10, 50},
Exists: true,
@ -300,18 +341,6 @@ func TestDiffFieldReader(t *testing.T) {
"setDeep": {
[]string{"setDeep"},
&Schema{
Type: TypeSet,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{Type: TypeInt},
"value": &Schema{Type: TypeString},
},
},
Set: func(a interface{}) int {
return a.(map[string]interface{})["index"].(int)
},
},
FieldReadResult{
Value: []interface{}{
map[string]interface{}{
@ -331,12 +360,6 @@ func TestDiffFieldReader(t *testing.T) {
"listMapRemoval": {
[]string{"listMap"},
&Schema{
Type: TypeList,
Elem: &Schema{
Type: TypeMap,
},
},
FieldReadResult{
Value: []interface{}{
map[string]interface{}{
@ -353,27 +376,6 @@ func TestDiffFieldReader(t *testing.T) {
"setChange": {
[]string{"setChange"},
&Schema{
Type: TypeSet,
Optional: true,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{
Type: TypeInt,
Required: true,
},
"value": &Schema{
Type: TypeString,
Required: true,
},
},
},
Set: func(a interface{}) int {
m := a.(map[string]interface{})
return m["index"].(int)
},
},
FieldReadResult{
Value: []interface{}{
map[string]interface{}{
@ -388,7 +390,7 @@ func TestDiffFieldReader(t *testing.T) {
}
for name, tc := range cases {
out, err := r.ReadField(tc.Addr, tc.Schema)
out, err := r.ReadField(tc.Addr)
if (err != nil) != tc.Err {
t.Fatalf("%s: err: %s", name, err)
}

View File

@ -8,12 +8,16 @@ import (
// MapFieldReader reads fields out of an untyped map[string]string to
// the best of its ability.
type MapFieldReader struct {
Map map[string]string
Map map[string]string
Schema map[string]*Schema
}
func (r *MapFieldReader) ReadField(
address []string, schema *Schema) (FieldReadResult, error) {
func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) {
k := strings.Join(address, ".")
schema := addrToSchema(address, r.Schema)
if schema == nil {
return FieldReadResult{}, nil
}
switch schema.Type {
case TypeBool:
@ -23,13 +27,13 @@ func (r *MapFieldReader) ReadField(
case TypeString:
return r.readPrimitive(k, schema)
case TypeList:
return readListField(r, k, schema)
return readListField(r, address, schema)
case TypeMap:
return r.readMap(k)
case TypeSet:
return r.readSet(k, schema)
case typeObject:
return readObjectField(r, k, schema.Elem.(map[string]*Schema))
return readObjectField(r, address, schema.Elem.(map[string]*Schema))
default:
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
}
@ -102,18 +106,6 @@ func (r *MapFieldReader) readSet(
}, nil
}
// Get the schema for the elements
var elemSchema *Schema
switch t := schema.Elem.(type) {
case *Resource:
elemSchema = &Schema{
Type: typeObject,
Elem: t.Schema,
}
case *Schema:
elemSchema = t
}
// Go through the map and find all the set items
prefix := k + "."
for k, _ := range r.Map {
@ -129,7 +121,7 @@ func (r *MapFieldReader) readSet(
parts := strings.Split(k[len(prefix):], ".")
idx := parts[0]
raw, err := r.ReadField([]string{prefix + idx}, elemSchema)
raw, err := r.ReadField([]string{prefix[:len(prefix)-1], idx})
if err != nil {
return FieldReadResult{}, err
}

View File

@ -11,6 +11,40 @@ func TestMapFieldReader_impl(t *testing.T) {
func TestMapFieldReader(t *testing.T) {
r := &MapFieldReader{
Schema: map[string]*Schema{
"bool": &Schema{Type: TypeBool},
"int": &Schema{Type: TypeInt},
"string": &Schema{Type: TypeString},
"list": &Schema{
Type: TypeList,
Elem: &Schema{Type: TypeString},
},
"listInt": &Schema{
Type: TypeList,
Elem: &Schema{Type: TypeInt},
},
"map": &Schema{Type: TypeMap},
"set": &Schema{
Type: TypeSet,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int {
return a.(int)
},
},
"setDeep": &Schema{
Type: TypeSet,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{Type: TypeInt},
"value": &Schema{Type: TypeString},
},
},
Set: func(a interface{}) int {
return a.(map[string]interface{})["index"].(int)
},
},
},
Map: map[string]string{
"bool": "true",
"int": "42",
@ -41,7 +75,6 @@ func TestMapFieldReader(t *testing.T) {
cases := map[string]struct {
Addr []string
Schema *Schema
Out interface{}
OutOk bool
OutComputed bool
@ -49,7 +82,6 @@ func TestMapFieldReader(t *testing.T) {
}{
"noexist": {
[]string{"boolNOPE"},
&Schema{Type: TypeBool},
nil,
false,
false,
@ -58,7 +90,6 @@ func TestMapFieldReader(t *testing.T) {
"bool": {
[]string{"bool"},
&Schema{Type: TypeBool},
true,
true,
false,
@ -67,7 +98,6 @@ func TestMapFieldReader(t *testing.T) {
"int": {
[]string{"int"},
&Schema{Type: TypeInt},
42,
true,
false,
@ -76,7 +106,6 @@ func TestMapFieldReader(t *testing.T) {
"string": {
[]string{"string"},
&Schema{Type: TypeString},
"string",
true,
false,
@ -85,10 +114,6 @@ func TestMapFieldReader(t *testing.T) {
"list": {
[]string{"list"},
&Schema{
Type: TypeList,
Elem: &Schema{Type: TypeString},
},
[]interface{}{
"foo",
"bar",
@ -100,10 +125,6 @@ func TestMapFieldReader(t *testing.T) {
"listInt": {
[]string{"listInt"},
&Schema{
Type: TypeList,
Elem: &Schema{Type: TypeInt},
},
[]interface{}{
21,
42,
@ -115,7 +136,6 @@ func TestMapFieldReader(t *testing.T) {
"map": {
[]string{"map"},
&Schema{Type: TypeMap},
map[string]interface{}{
"foo": "bar",
"bar": "baz",
@ -127,7 +147,6 @@ func TestMapFieldReader(t *testing.T) {
"mapelem": {
[]string{"map", "foo"},
&Schema{Type: TypeString},
"bar",
true,
false,
@ -136,13 +155,6 @@ func TestMapFieldReader(t *testing.T) {
"set": {
[]string{"set"},
&Schema{
Type: TypeSet,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int {
return a.(int)
},
},
[]interface{}{10, 50},
true,
false,
@ -151,18 +163,6 @@ func TestMapFieldReader(t *testing.T) {
"setDeep": {
[]string{"setDeep"},
&Schema{
Type: TypeSet,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{Type: TypeInt},
"value": &Schema{Type: TypeString},
},
},
Set: func(a interface{}) int {
return a.(map[string]interface{})["index"].(int)
},
},
[]interface{}{
map[string]interface{}{
"index": 10,
@ -180,7 +180,7 @@ func TestMapFieldReader(t *testing.T) {
}
for name, tc := range cases {
out, err := r.ReadField(tc.Addr, tc.Schema)
out, err := r.ReadField(tc.Addr)
if (err != nil) != tc.OutErr {
t.Fatalf("%s: err: %s", name, err)
}

View File

@ -16,20 +16,19 @@ type MultiLevelFieldReader struct {
Levels []string
}
func (r *MultiLevelFieldReader) ReadField(
address []string, schema *Schema) (FieldReadResult, error) {
return r.ReadFieldMerge(address, schema, r.Levels[len(r.Levels)-1])
func (r *MultiLevelFieldReader) ReadField(address []string) (FieldReadResult, error) {
return r.ReadFieldMerge(address, r.Levels[len(r.Levels)-1])
}
func (r *MultiLevelFieldReader) ReadFieldExact(
address []string, schema *Schema, level string) (FieldReadResult, error) {
address []string, level string) (FieldReadResult, error) {
reader, ok := r.Readers[level]
if !ok {
return FieldReadResult{}, fmt.Errorf(
"Unknown reader level: %s", level)
}
result, err := reader.ReadField(address, schema)
result, err := reader.ReadField(address)
if err != nil {
return FieldReadResult{}, fmt.Errorf(
"Error reading level %s: %s", level, err)
@ -39,7 +38,7 @@ func (r *MultiLevelFieldReader) ReadFieldExact(
}
func (r *MultiLevelFieldReader) ReadFieldMerge(
address []string, schema *Schema, level string) (FieldReadResult, error) {
address []string, level string) (FieldReadResult, error) {
var result FieldReadResult
for _, l := range r.Levels {
r, ok := r.Readers[l]
@ -47,7 +46,7 @@ func (r *MultiLevelFieldReader) ReadFieldMerge(
continue
}
out, err := r.ReadField(address, schema)
out, err := r.ReadField(address)
if err != nil {
return FieldReadResult{}, fmt.Errorf(
"Error reading level %s: %s", l, err)

View File

@ -11,7 +11,6 @@ import (
func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
cases := map[string]struct {
Addr []string
Schema *Schema
Readers []FieldReader
Level string
Result FieldReadResult
@ -19,22 +18,27 @@ func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
"specific": {
Addr: []string{"foo"},
Schema: &Schema{
Type: TypeString,
},
Readers: []FieldReader{
&MapFieldReader{
Schema: map[string]*Schema{
"foo": &Schema{Type: TypeString},
},
Map: map[string]string{
"foo": "bar",
},
},
&MapFieldReader{
Schema: map[string]*Schema{
"foo": &Schema{Type: TypeString},
},
Map: map[string]string{
"foo": "baz",
},
},
&MapFieldReader{
Schema: map[string]*Schema{
"foo": &Schema{Type: TypeString},
},
Map: map[string]string{},
},
},
@ -61,7 +65,7 @@ func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
Levels: levels,
}
out, err := r.ReadFieldExact(tc.Addr, tc.Schema, tc.Level)
out, err := r.ReadFieldExact(tc.Addr, tc.Level)
if err != nil {
t.Fatalf("%s: err: %s", name, err)
}
@ -75,23 +79,22 @@ func TestMultiLevelFieldReaderReadFieldExact(t *testing.T) {
func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
cases := map[string]struct {
Addr []string
Schema *Schema
Readers []FieldReader
Result FieldReadResult
}{
"stringInDiff": {
Addr: []string{"availability_zone"},
Schema: &Schema{
Type: TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
Readers: []FieldReader{
&DiffFieldReader{
Schema: map[string]*Schema{
"availability_zone": &Schema{Type: TypeString},
},
Source: &MapFieldReader{
Schema: map[string]*Schema{
"availability_zone": &Schema{Type: TypeString},
},
Map: map[string]string{
"availability_zone": "foo",
},
@ -118,22 +121,27 @@ func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
"lastLevelComputed": {
Addr: []string{"availability_zone"},
Schema: &Schema{
Type: TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
Readers: []FieldReader{
&MapFieldReader{
Schema: map[string]*Schema{
"availability_zone": &Schema{Type: TypeString},
},
Map: map[string]string{
"availability_zone": "foo",
},
},
&DiffFieldReader{
Schema: map[string]*Schema{
"availability_zone": &Schema{Type: TypeString},
},
Source: &MapFieldReader{
Schema: map[string]*Schema{
"availability_zone": &Schema{Type: TypeString},
},
Map: map[string]string{
"availability_zone": "foo",
},
@ -161,18 +169,23 @@ func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
"list of maps with removal in diff": {
Addr: []string{"config_vars"},
Schema: &Schema{
Type: TypeList,
Optional: true,
Computed: true,
Elem: &Schema{
Type: TypeMap,
},
},
Readers: []FieldReader{
&DiffFieldReader{
Schema: map[string]*Schema{
"config_vars": &Schema{
Type: TypeList,
Elem: &Schema{Type: TypeMap},
},
},
Source: &MapFieldReader{
Schema: map[string]*Schema{
"config_vars": &Schema{
Type: TypeList,
Elem: &Schema{Type: TypeMap},
},
},
Map: map[string]string{
"config_vars.#": "2",
"config_vars.0.foo": "bar",
@ -207,17 +220,19 @@ func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
"first level only": {
Addr: []string{"foo"},
Schema: &Schema{
Type: TypeString,
},
Readers: []FieldReader{
&MapFieldReader{
Schema: map[string]*Schema{
"foo": &Schema{Type: TypeString},
},
Map: map[string]string{
"foo": "bar",
},
},
&MapFieldReader{
Schema: map[string]*Schema{
"foo": &Schema{Type: TypeString},
},
Map: map[string]string{},
},
},
@ -243,7 +258,7 @@ func TestMultiLevelFieldReaderReadFieldMerge(t *testing.T) {
Levels: levels,
}
out, err := r.ReadFieldMerge(tc.Addr, tc.Schema, levels[len(levels)-1])
out, err := r.ReadFieldMerge(tc.Addr, levels[len(levels)-1])
if err != nil {
t.Fatalf("%s: err: %s", name, err)
}

View File

@ -0,0 +1,48 @@
package schema
import (
"reflect"
"testing"
)
func TestAddrToSchema(t *testing.T) {
cases := map[string]struct {
Addr []string
Schema map[string]*Schema
Result *Schema
}{
"mapElem": {
[]string{"map", "foo"},
map[string]*Schema{
"map": &Schema{Type: TypeMap},
},
&Schema{Type: TypeString},
},
"setDeep": {
[]string{"set", "50", "index"},
map[string]*Schema{
"set": &Schema{
Type: TypeSet,
Elem: &Resource{
Schema: map[string]*Schema{
"index": &Schema{Type: TypeInt},
"value": &Schema{Type: TypeString},
},
},
Set: func(a interface{}) int {
return a.(map[string]interface{})["index"].(int)
},
},
},
&Schema{Type: TypeInt},
},
}
for name, tc := range cases {
result := addrToSchema(tc.Addr, tc.Schema)
if !reflect.DeepEqual(result, tc.Result) {
t.Fatalf("%s: %#v", name, result)
}
}
}