From 44a45b7332562dd9ca7314f328d57f9b7a577d1b Mon Sep 17 00:00:00 2001 From: Farid Neshat Date: Wed, 5 Dec 2018 09:26:57 +0100 Subject: [PATCH] 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 --- helper/schema/field_writer_map.go | 7 ++-- helper/schema/resource_data_test.go | 63 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/helper/schema/field_writer_map.go b/helper/schema/field_writer_map.go index 814c7ba8e3fc..08ee11c37121 100644 --- a/helper/schema/field_writer_map.go +++ b/helper/schema/field_writer_map.go @@ -297,13 +297,14 @@ func (w *MapFieldWriter) setSet( // we get the proper order back based on the hash code. if v := reflect.ValueOf(value); v.Kind() == reflect.Slice { // Build a temp *ResourceData to use for the conversion + tempAddr := addr[len(addr)-1:] tempSchema := *schema tempSchema.Type = TypeList - tempSchemaMap := map[string]*Schema{addr[0]: &tempSchema} + tempSchemaMap := map[string]*Schema{tempAddr[0]: &tempSchema} tempW := &MapFieldWriter{Schema: tempSchemaMap} // 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 } @@ -319,7 +320,7 @@ func (w *MapFieldWriter) setSet( } for i := 0; i < v.Len(); i++ { is := strconv.FormatInt(int64(i), 10) - result, err := tempR.ReadField(append(addrCopy, is)) + result, err := tempR.ReadField(append(tempAddr, is)) if err != nil { return err } diff --git a/helper/schema/resource_data_test.go b/helper/schema/resource_data_test.go index 6ef19017d2cc..29d665746cd9 100644 --- a/helper/schema/resource_data_test.go +++ b/helper/schema/resource_data_test.go @@ -2059,6 +2059,69 @@ func TestResourceDataSet(t *testing.T) { GetKey: "availability_zone", 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)