From 7b51bc99bd94314ec8e0b1e8ac8f94e0c8b73aac Mon Sep 17 00:00:00 2001 From: Shawn Wang Date: Tue, 21 May 2024 12:09:16 -0700 Subject: [PATCH] Add support of type set and improve UT Signed-off-by: Shawn Wang --- nsxt/metadata/metadata.go | 29 ++++- nsxt/metadata/metadata_test.go | 224 +++++++++++++++++++++++++++++++-- 2 files changed, 237 insertions(+), 16 deletions(-) diff --git a/nsxt/metadata/metadata.go b/nsxt/metadata/metadata.go index d30d43557..a1997c98c 100644 --- a/nsxt/metadata/metadata.go +++ b/nsxt/metadata/metadata.go @@ -147,10 +147,16 @@ func StructToSchema(elem reflect.Value, d *schema.ResourceData, metadata map[str // currently supports nested subtype and trivial types func SchemaToStruct(elem reflect.Value, d *schema.ResourceData, metadata map[string]*ExtendedSchema, parent string, parentMap map[string]interface{}) { for key, item := range metadata { - if item.Metadata.ReadOnly || item.Metadata.Skip { + if item.Metadata.ReadOnly { + log.Printf("[INFO] skip key %s as read only", key) + continue + } + if item.Metadata.Skip { + log.Printf("[INFO] skip key %s", key) continue } if item.Metadata.IntroducedInVersion != "" && util.NsxVersionLower(item.Metadata.IntroducedInVersion) { + log.Printf("[INFO] skip key %s as NSX does not have support", key) continue } @@ -208,11 +214,20 @@ func SchemaToStruct(elem reflect.Value, d *schema.ResourceData, metadata map[str } if item.Metadata.SchemaType == "list" || item.Metadata.SchemaType == "set" { var itemList []interface{} - if len(parent) > 0 { - itemList = parentMap[key].([]interface{}) + if item.Metadata.SchemaType == "list" { + if len(parent) > 0 { + itemList = parentMap[key].([]interface{}) + } else { + itemList = d.Get(key).([]interface{}) + } } else { - itemList = d.Get(key).([]interface{}) + if len(parent) > 0 { + itemList = parentMap[key].(*schema.Set).List() + } else { + itemList = d.Get(key).(*schema.Set).List() + } } + if len(itemList) == 0 { continue } @@ -233,7 +248,11 @@ func SchemaToStruct(elem reflect.Value, d *schema.ResourceData, metadata map[str } for i, v := range itemList { - sliceElem.Index(i).Set(reflect.ValueOf(v)) + if childElem.Metadata.SchemaType == "int" { + sliceElem.Index(i).Set(reflect.ValueOf(v).Convert(reflect.TypeOf(int64(0)))) + } else { + sliceElem.Index(i).Set(reflect.ValueOf(v)) + } log.Printf("[INFO] appending %v to %s", v, key) } } diff --git a/nsxt/metadata/metadata_test.go b/nsxt/metadata/metadata_test.go index 57039a401..f82d13e23 100644 --- a/nsxt/metadata/metadata_test.go +++ b/nsxt/metadata/metadata_test.go @@ -18,7 +18,13 @@ type testStruct struct { IntFieldNil *int64 StructField *testNestedStruct StringListField []string + BoolListField []bool + IntListField []int64 StructList []testNestedStruct + StringSetField []string + BoolSetField []bool + IntSetField []int64 + StructSet []testNestedStruct DeepNestedStruct *testDeepNestedStruct } @@ -31,6 +37,7 @@ type testNestedStruct struct { type testDeepNestedStruct struct { StringField *string BoolList []bool + IntSet []int64 StructList []testNestedStruct } @@ -79,6 +86,18 @@ var testSchema = map[string]*schema.Schema{ Type: schema.TypeString, }, }, + "bool_list": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeBool, + }, + }, + "int_list": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, "struct_list": { Type: schema.TypeList, Elem: &schema.Resource{ @@ -95,6 +114,40 @@ var testSchema = map[string]*schema.Schema{ }, }, }, + "string_set": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "bool_set": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeBool, + }, + }, + "int_set": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + "struct_set": { + Type: schema.TypeSet, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "string_field": { + Type: schema.TypeString, + }, + "bool_field": { + Type: schema.TypeBool, + }, + "int_field": { + Type: schema.TypeInt, + }, + }, + }, + }, "deep_nested_struct": { Type: schema.TypeList, MaxItems: 1, @@ -109,6 +162,12 @@ var testSchema = map[string]*schema.Schema{ Type: schema.TypeBool, }, }, + "int_set": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, "struct_list": { Type: schema.TypeList, Elem: &schema.Resource{ @@ -169,10 +228,17 @@ func basicIntSchema(sdkName string, optional bool) *ExtendedSchema { } } -func basicStructSchema() schema.Schema { +func basicStructSchema(t string) schema.Schema { + schemaType := schema.TypeList + maxItems := 0 + if t == "set" { + schemaType = schema.TypeSet + } else if t == "struct" { + maxItems = 1 + } return schema.Schema{ - Type: schema.TypeList, - MaxItems: 1, + Type: schemaType, + MaxItems: maxItems, Elem: &ExtendedResource{ Schema: map[string]*ExtendedSchema{ "string_field": basicStringSchema("StringField", false), @@ -200,8 +266,18 @@ func mixedStructSchema() schema.Schema { SdkFieldName: "BoolList", }, }, + "int_set": { + Schema: schema.Schema{ + Type: schema.TypeSet, + Elem: basicIntSchema("IntSet", false), + }, + Metadata: Metadata{ + SchemaType: "set", + SdkFieldName: "IntSet", + }, + }, "struct_list": { - Schema: basicStructSchema(), + Schema: basicStructSchema("list"), Metadata: Metadata{ SchemaType: "list", SdkFieldName: "StructList", @@ -221,7 +297,7 @@ var testExtendedSchema = map[string]*ExtendedSchema{ "bool_field_nil": basicBoolSchema("BoolFieldNil", true), "int_field_nil": basicIntSchema("IntFieldNil", true), "struct_field": { - Schema: basicStructSchema(), + Schema: basicStructSchema("struct"), Metadata: Metadata{ SchemaType: "struct", SdkFieldName: "StructField", @@ -238,14 +314,72 @@ var testExtendedSchema = map[string]*ExtendedSchema{ SdkFieldName: "StringListField", }, }, + "bool_list": { + Schema: schema.Schema{ + Type: schema.TypeList, + Elem: basicBoolSchema("BoolListField", false), + }, + Metadata: Metadata{ + SchemaType: "list", + SdkFieldName: "BoolListField", + }, + }, + "int_list": { + Schema: schema.Schema{ + Type: schema.TypeList, + Elem: basicIntSchema("IntListField", false), + }, + Metadata: Metadata{ + SchemaType: "list", + SdkFieldName: "IntListField", + }, + }, "struct_list": { - Schema: basicStructSchema(), + Schema: basicStructSchema("list"), Metadata: Metadata{ SchemaType: "list", SdkFieldName: "StructList", ReflectType: reflect.TypeOf(testNestedStruct{}), }, }, + "string_set": { + Schema: schema.Schema{ + Type: schema.TypeSet, + Elem: basicStringSchema("StringSetField", false), + }, + Metadata: Metadata{ + SchemaType: "set", + SdkFieldName: "StringSetField", + }, + }, + "bool_set": { + Schema: schema.Schema{ + Type: schema.TypeSet, + Elem: basicBoolSchema("BoolSetField", false), + }, + Metadata: Metadata{ + SchemaType: "set", + SdkFieldName: "BoolSetField", + }, + }, + "int_set": { + Schema: schema.Schema{ + Type: schema.TypeSet, + Elem: basicIntSchema("IntSetField", false), + }, + Metadata: Metadata{ + SchemaType: "set", + SdkFieldName: "IntSetField", + }, + }, + "struct_set": { + Schema: basicStructSchema("set"), + Metadata: Metadata{ + SchemaType: "set", + SdkFieldName: "StructSet", + ReflectType: reflect.TypeOf(testNestedStruct{}), + }, + }, "deep_nested_struct": { Schema: mixedStructSchema(), Metadata: Metadata{ @@ -285,11 +419,11 @@ func assertSchemaEqual(t *testing.T, expected, actual map[string]*schema.Schema) func TestStructToSchema(t *testing.T) { testStr := "test_string" - nestStr1, nestStr2 := "nest_str1", "nest_str2" + nestStr1, nestStr2, nestStr3 := "nest_str1", "nest_str2", "nest_str3" testBool := true nestBool1, nestBool2 := true, false testInt := int64(123) - nestInt1, nestInt2 := int64(123), int64(456) + nestInt1, nestInt2, nestInt3 := int64(123), int64(456), int64(789) obj := testStruct{ StringField: &testStr, BoolField: &testBool, @@ -300,6 +434,11 @@ func TestStructToSchema(t *testing.T) { IntField: &testInt, }, StringListField: []string{"string_1", "string_2"}, + BoolListField: []bool{true, false}, + IntListField: []int64{123, 456}, + StringSetField: []string{"string_3"}, + BoolSetField: []bool{true}, + IntSetField: []int64{789}, StructList: []testNestedStruct{ { StringField: &nestStr1, @@ -312,9 +451,17 @@ func TestStructToSchema(t *testing.T) { IntField: &nestInt2, }, }, + StructSet: []testNestedStruct{ + { + StringField: &nestStr3, + BoolField: &nestBool2, + IntField: &nestInt3, + }, + }, DeepNestedStruct: &testDeepNestedStruct{ StringField: &nestStr2, BoolList: []bool{false, true}, + IntSet: []int64{135}, StructList: []testNestedStruct{ { StringField: &nestStr1, @@ -355,6 +502,19 @@ func TestStructToSchema(t *testing.T) { t.Run("Base list", func(t *testing.T) { stringSlice := d.Get("string_list").([]interface{}) assert.Equal(t, []interface{}{"string_1", "string_2"}, stringSlice) + boolSlice := d.Get("bool_list").([]interface{}) + assert.Equal(t, []interface{}{true, false}, boolSlice) + intSlice := d.Get("int_list").([]interface{}) + assert.Equal(t, []interface{}{123, 456}, intSlice) + }) + + t.Run("Base set", func(t *testing.T) { + stringSlice := d.Get("string_set").(*schema.Set).List() + assert.Equal(t, []interface{}{"string_3"}, stringSlice) + boolSlice := d.Get("bool_set").(*schema.Set).List() + assert.Equal(t, []interface{}{true}, boolSlice) + intSlice := d.Get("int_set").(*schema.Set).List() + assert.Equal(t, []interface{}{789}, intSlice) }) t.Run("Struct list", func(t *testing.T) { @@ -372,10 +532,21 @@ func TestStructToSchema(t *testing.T) { }, structSlice[1].(map[string]interface{})) }) + t.Run("Struct set", func(t *testing.T) { + structSlice := d.Get("struct_set").(*schema.Set).List() + assert.Equal(t, 1, len(structSlice)) + assert.Equal(t, map[string]interface{}{ + "string_field": nestStr3, + "bool_field": nestBool2, + "int_field": 789, + }, structSlice[0].(map[string]interface{})) + }) + t.Run("Deep nested struct", func(t *testing.T) { deepNestedObj := d.Get("deep_nested_struct").([]interface{})[0].(map[string]interface{}) assert.Equal(t, nestStr2, deepNestedObj["string_field"].(string)) assert.Equal(t, []interface{}{false, true}, deepNestedObj["bool_list"].([]interface{})) + assert.Equal(t, []interface{}{135}, deepNestedObj["int_set"].(*schema.Set).List()) nestedStructList := deepNestedObj["struct_list"].([]interface{}) assert.Equal(t, 1, len(nestedStructList)) assert.Equal(t, map[string]interface{}{ @@ -400,6 +571,11 @@ func TestSchemaToStruct(t *testing.T) { }, }, "string_list": []interface{}{"string_1", "string_2"}, + "bool_list": []interface{}{true, false}, + "int_list": []interface{}{123, 456}, + "string_set": []interface{}{"string_3"}, + "bool_set": []interface{}{true}, + "int_set": []interface{}{789}, "struct_list": []interface{}{ map[string]interface{}{ "string_field": "nested_string_1", @@ -412,10 +588,18 @@ func TestSchemaToStruct(t *testing.T) { "int_field": 2, }, }, + "struct_set": []interface{}{ + map[string]interface{}{ + "string_field": "nested_string_3", + "bool_field": false, + "int_field": 3, + }, + }, "deep_nested_struct": []interface{}{ map[string]interface{}{ "string_field": "nested_string_1", "bool_list": []interface{}{true, false}, + "int_set": []interface{}{135}, "struct_list": []interface{}{ map[string]interface{}{ "string_field": "nested_string_2", @@ -431,9 +615,9 @@ func TestSchemaToStruct(t *testing.T) { elem := reflect.ValueOf(&obj).Elem() SchemaToStruct(elem, d, testExtendedSchema, "", nil) - nestStr1, nestStr2 := "nested_string_1", "nested_string_2" - trueVal := true - intVal1, intVal2 := int64(1), int64(2) + nestStr1, nestStr2, nestStr3 := "nested_string_1", "nested_string_2", "nested_string_3" + trueVal, falseVal := true, false + intVal1, intVal2, intVal3 := int64(1), int64(2), int64(3) t.Run("Base types", func(t *testing.T) { assert.Equal(t, "test_string", *obj.StringField) @@ -455,6 +639,14 @@ func TestSchemaToStruct(t *testing.T) { t.Run("Base list", func(t *testing.T) { assert.Equal(t, []string{"string_1", "string_2"}, obj.StringListField) + assert.Equal(t, []bool{true, false}, obj.BoolListField) + assert.Equal(t, []int64{123, 456}, obj.IntListField) + }) + + t.Run("Base set", func(t *testing.T) { + assert.Equal(t, []string{"string_3"}, obj.StringSetField) + assert.Equal(t, []bool{true}, obj.BoolSetField) + assert.Equal(t, []int64{789}, obj.IntSetField) }) t.Run("Struct list", func(t *testing.T) { @@ -471,10 +663,20 @@ func TestSchemaToStruct(t *testing.T) { }, obj.StructList[1]) }) + t.Run("Struct set", func(t *testing.T) { + assert.Equal(t, 1, len(obj.StringSetField)) + assert.EqualValues(t, testNestedStruct{ + StringField: &nestStr3, + BoolField: &falseVal, + IntField: &intVal3, + }, obj.StructSet[0]) + }) + t.Run("Deep nested struct", func(t *testing.T) { assert.EqualValues(t, &testDeepNestedStruct{ StringField: &nestStr1, BoolList: []bool{true, false}, + IntSet: []int64{135}, StructList: []testNestedStruct{{ StringField: &nestStr2, BoolField: &trueVal,