helper/schema: Fix setting a set in a list

The added test in this commit, without the fix, will make d.Set return
the following error:

`Invalid address to set: []string{"ports", "0", "set"}`

This was due to the fact that setSet in feild_writer_map tried to
convert a slice into a set by creating a temp set schema and calling
writeField on that with the address(`[]string{"ports", "0", "set"}"` in
this case). However the temp schema was only for the set and not the
whole schema as seen in the address so, it should have been `[]string{"set"}"`
so it would align with the schema.

This commits adds another variable there(tempAddr) which will only
contain the last entry of the address that would be the set key, which
would match the created schema

This commit potentially fixes the problem described in #16331
This commit is contained in:
Farid Neshat 2018-12-05 09:26:57 +01:00
parent af9d046afb
commit 44a45b7332
2 changed files with 67 additions and 3 deletions

View File

@ -297,13 +297,14 @@ func (w *MapFieldWriter) setSet(
// we get the proper order back based on the hash code. // we get the proper order back based on the hash code.
if v := reflect.ValueOf(value); v.Kind() == reflect.Slice { if v := reflect.ValueOf(value); v.Kind() == reflect.Slice {
// Build a temp *ResourceData to use for the conversion // Build a temp *ResourceData to use for the conversion
tempAddr := addr[len(addr)-1:]
tempSchema := *schema tempSchema := *schema
tempSchema.Type = TypeList tempSchema.Type = TypeList
tempSchemaMap := map[string]*Schema{addr[0]: &tempSchema} tempSchemaMap := map[string]*Schema{tempAddr[0]: &tempSchema}
tempW := &MapFieldWriter{Schema: tempSchemaMap} tempW := &MapFieldWriter{Schema: tempSchemaMap}
// Set the entire list, this lets us get sane values out of it // Set the entire list, this lets us get sane values out of it
if err := tempW.WriteField(addr, value); err != nil { if err := tempW.WriteField(tempAddr, value); err != nil {
return err return err
} }
@ -319,7 +320,7 @@ func (w *MapFieldWriter) setSet(
} }
for i := 0; i < v.Len(); i++ { for i := 0; i < v.Len(); i++ {
is := strconv.FormatInt(int64(i), 10) is := strconv.FormatInt(int64(i), 10)
result, err := tempR.ReadField(append(addrCopy, is)) result, err := tempR.ReadField(append(tempAddr, is))
if err != nil { if err != nil {
return err return err
} }

View File

@ -2059,6 +2059,69 @@ func TestResourceDataSet(t *testing.T) {
GetKey: "availability_zone", GetKey: "availability_zone",
GetValue: "", GetValue: "",
}, },
// #16: Set in a list
{
Schema: map[string]*Schema{
"ports": &Schema{
Type: TypeList,
Elem: &Resource{
Schema: map[string]*Schema{
"set": &Schema{
Type: TypeSet,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int {
return a.(int)
},
},
},
},
},
},
State: nil,
Key: "ports",
Value: []interface{}{
map[string]interface{}{
"set": []interface{}{
1,
},
},
},
GetKey: "ports",
GetValue: []interface{}{
map[string]interface{}{
"set": []interface{}{
1,
},
},
},
GetPreProcess: func(v interface{}) interface{} {
if v == nil {
return v
}
s, ok := v.([]interface{})
if !ok {
return v
}
for _, v := range s {
m, ok := v.(map[string]interface{})
if !ok {
continue
}
if m["set"] == nil {
continue
}
if s, ok := m["set"].(*Set); ok {
m["set"] = s.List()
}
}
return v
},
},
} }
oldEnv := os.Getenv(PanicOnErr) oldEnv := os.Getenv(PanicOnErr)