Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: move resource data change detectors to separate package #521

Merged
merged 1 commit into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 0 additions & 55 deletions equinix/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package equinix
import (
"context"
"fmt"
"reflect"
"strings"
"time"

Expand All @@ -24,15 +23,6 @@ var (
NetworkTypeListHB = strings.Join(DeviceNetworkTypesHB, ", ")
)

// resourceDataProvider provies interface to schema.ResourceData
// for convenient mocking purposes
type resourceDataProvider interface {
Get(key string) interface{}
GetOk(key string) (interface{}, bool)
HasChange(key string) bool
GetChange(key string) (interface{}, interface{})
}

// Provider returns Equinix terraform *schema.Provider
func Provider() *schema.Provider {
provider := &schema.Provider{
Expand Down Expand Up @@ -249,40 +239,6 @@ func isStringInSlice(needle string, hay []string) bool {
return false
}

func getResourceDataChangedKeys(keys []string, d resourceDataProvider) map[string]interface{} {
changed := make(map[string]interface{})
for _, key := range keys {
if v := d.Get(key); v != nil && d.HasChange(key) {
changed[key] = v
}
}
return changed
}

func getResourceDataListElementChanges(keys []string, listKeyName string, listIndex int, d resourceDataProvider) map[string]interface{} {
changed := make(map[string]interface{})
if !d.HasChange(listKeyName) {
return changed
}
old, new := d.GetChange(listKeyName)
oldList := old.([]interface{})
newList := new.([]interface{})
if len(oldList) < listIndex || len(newList) < listIndex {
return changed
}
return getMapChangedKeys(keys, oldList[listIndex].(map[string]interface{}), newList[listIndex].(map[string]interface{}))
}

func getMapChangedKeys(keys []string, old, new map[string]interface{}) map[string]interface{} {
changed := make(map[string]interface{})
for _, key := range keys {
if !reflect.DeepEqual(old[key], new[key]) {
changed[key] = new[key]
}
}
return changed
}

func isEmpty(v interface{}) bool {
switch v := v.(type) {
case int:
Expand Down Expand Up @@ -347,14 +303,3 @@ func slicesMatchCaseInsensitive(s1, s2 []string) bool {
}
return true
}

func schemaSetToMap(set *schema.Set) map[int]interface{} {
transformed := make(map[int]interface{})
if set != nil {
list := set.List()
for i := range list {
transformed[set.F(list[i])] = list[i]
}
}
return transformed
}
128 changes: 1 addition & 127 deletions equinix/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ package equinix
import (
"fmt"
"os"
"reflect"
"regexp"
"strings"
"testing"

"github.com/equinix/terraform-provider-equinix/internal/config"
"github.com/equinix/terraform-provider-equinix/internal/hashcode"

"github.com/equinix/ecx-go/v2"
"github.com/equinix/terraform-provider-equinix/internal/config"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/stretchr/testify/assert"
Expand All @@ -24,28 +21,6 @@ var (
testExternalProviders map[string]resource.ExternalProvider
)

type mockedResourceDataProvider struct {
actual map[string]interface{}
old map[string]interface{}
}

func (r mockedResourceDataProvider) Get(key string) interface{} {
return r.actual[key]
}

func (r mockedResourceDataProvider) GetOk(key string) (interface{}, bool) {
v, ok := r.actual[key]
return v, ok
}

func (r mockedResourceDataProvider) HasChange(key string) bool {
return !reflect.DeepEqual(r.old[key], r.actual[key])
}

func (r mockedResourceDataProvider) GetChange(key string) (interface{}, interface{}) {
return r.old[key], r.actual[key]
}

type mockECXClient struct {
GetUserPortsFn func() ([]ecx.Port, error)

Expand Down Expand Up @@ -176,82 +151,6 @@ func TestProvider_stringsFound_negative(t *testing.T) {
assert.False(t, result, "Given strings were found")
}

func TestProvider_resourceDataChangedKeys(t *testing.T) {
// given
keys := []string{"key", "keyTwo", "keyThree"}
rd := mockedResourceDataProvider{
actual: map[string]interface{}{
"key": "value",
"keyTwo": "newValueTwo",
},
old: map[string]interface{}{
"key": "value",
"keyTwo": "valueTwo",
},
}
expected := map[string]interface{}{
"keyTwo": "newValueTwo",
}
// when
result := getResourceDataChangedKeys(keys, rd)
// then
assert.Equal(t, expected, result, "Function returns valid key changes")
}

func TestProvider_resourceDataListElementChanges(t *testing.T) {
// given
keys := []string{"key", "keyTwo", "keyThree"}
listKeyName := "myList"
rd := mockedResourceDataProvider{
old: map[string]interface{}{
listKeyName: []interface{}{
map[string]interface{}{
"key": "value",
"keyTwo": "valueTwo",
"keyThree": 50,
},
},
},
actual: map[string]interface{}{
listKeyName: []interface{}{
map[string]interface{}{
"key": "value",
"keyTwo": "newValueTwo",
"keyThree": 100,
},
},
},
}
expected := map[string]interface{}{
"keyTwo": "newValueTwo",
"keyThree": 100,
}
// when
result := getResourceDataListElementChanges(keys, listKeyName, 0, rd)
// then
assert.Equal(t, expected, result, "Function returns valid key changes")
}

func TestProvider_mapChanges(t *testing.T) {
// given
keys := []string{"key", "keyTwo", "keyThree"}
old := map[string]interface{}{
"key": "value",
"keyTwo": "valueTwo",
}
new := map[string]interface{}{
"key": "newValue",
"keyTwo": "valueTwo",
}
expected := map[string]interface{}{
"key": "newValue",
}
// when
result := getMapChangedKeys(keys, old, new)
// then
assert.Equal(t, expected, result, "Function returns valid key changes")
}

func TestProvider_isEmpty(t *testing.T) {
// given
input := []interface{}{
Expand Down Expand Up @@ -331,31 +230,6 @@ func TestProvider_slicesMatch(t *testing.T) {
}
}

func TestProvider_schemaSetToMap(t *testing.T) {
// given
type item struct {
id string
valueOne int
valueTwo int
}
setFunc := func(v interface{}) int {
i := v.(item)
return hashcode.String(i.id)
}
items := []interface{}{
item{"id1", 100, 200},
item{"id2", 666, 999},
item{"id3", 0, 100},
}
set := schema.NewSet(setFunc, items)
// when
list := schemaSetToMap(set)
// then
assert.Equal(t, items[0], list[setFunc(items[0])])
assert.Equal(t, items[1], list[setFunc(items[1])])
assert.Equal(t, items[2], list[setFunc(items[2])])
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Test helper functions
//_______________________________________________________________________
Expand Down
5 changes: 3 additions & 2 deletions equinix/resource_ecx_l2_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/equinix/terraform-provider-equinix/internal/config"
"github.com/equinix/terraform-provider-equinix/internal/converters"
equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors"
equinix_schema "github.com/equinix/terraform-provider-equinix/internal/schema"
equinix_validation "github.com/equinix/terraform-provider-equinix/internal/validation"

"github.com/equinix/ecx-go/v2"
Expand Down Expand Up @@ -755,13 +756,13 @@ func resourceECXL2ConnectionUpdate(ctx context.Context, d *schema.ResourceData,
ecxL2ConnectionSchemaNames["Speed"],
ecxL2ConnectionSchemaNames["SpeedUnit"],
}
primaryChanges := getResourceDataChangedKeys(supportedChanges, d)
primaryChanges := equinix_schema.GetResourceDataChangedKeys(supportedChanges, d)
primaryUpdateReq := client.NewL2ConnectionUpdateRequest(d.Id())
if err := fillFabricL2ConnectionUpdateRequest(primaryUpdateReq, primaryChanges).Execute(); err != nil {
return diag.FromErr(err)
}
if redID, ok := d.GetOk(ecxL2ConnectionSchemaNames["RedundantUUID"]); ok {
secondaryChanges := getResourceDataListElementChanges(supportedChanges, ecxL2ConnectionSchemaNames["SecondaryConnection"], 0, d)
secondaryChanges := equinix_schema.GetResourceDataListElementChanges(supportedChanges, ecxL2ConnectionSchemaNames["SecondaryConnection"], 0, d)
secondaryUpdateReq := client.NewL2ConnectionUpdateRequest(redID.(string))
if err := fillFabricL2ConnectionUpdateRequest(secondaryUpdateReq, secondaryChanges).Execute(); err != nil {
return diag.FromErr(err)
Expand Down
2 changes: 1 addition & 1 deletion equinix/resource_metal_organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func resourceMetalOrganizationUpdate(d *schema.ResourceData, meta interface{}) e
meta.(*config.Config).AddModuleToMetalUserAgent(d)
client := meta.(*config.Config).Metal

changes := getResourceDataChangedKeys([]string{"name", "description", "website", "twitter", "logo", "address"}, d)
changes := equinix_schema.GetResourceDataChangedKeys([]string{"name", "description", "website", "twitter", "logo", "address"}, d)
updateRequest := &packngo.OrganizationUpdateRequest{}
for change, changeValue := range changes {
switch change {
Expand Down
7 changes: 4 additions & 3 deletions equinix/resource_network_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/equinix/terraform-provider-equinix/internal/config"
"github.com/equinix/terraform-provider-equinix/internal/converters"
equinix_schema "github.com/equinix/terraform-provider-equinix/internal/schema"
equinix_validation "github.com/equinix/terraform-provider-equinix/internal/validation"

"github.com/equinix/ne-go"
Expand Down Expand Up @@ -965,11 +966,11 @@ func resourceNetworkDeviceUpdate(ctx context.Context, d *schema.ResourceData, m
neDeviceSchemaNames["ACLTemplateUUID"], neDeviceSchemaNames["MgmtAclTemplateUuid"],
}
updateReq := client.NewDeviceUpdateRequest(d.Id())
primaryChanges := getResourceDataChangedKeys(supportedChanges, d)
primaryChanges := equinix_schema.GetResourceDataChangedKeys(supportedChanges, d)
var clusterChanges map[string]interface{}
clusterSupportedChanges := []string{neDeviceClusterSchemaNames["ClusterName"]}
if _, ok := d.GetOk(neDeviceSchemaNames["ClusterDetails"]); ok {
clusterChanges = getResourceDataListElementChanges(clusterSupportedChanges, neDeviceSchemaNames["ClusterDetails"], 0, d)
clusterChanges = equinix_schema.GetResourceDataListElementChanges(clusterSupportedChanges, neDeviceSchemaNames["ClusterDetails"], 0, d)
for key, value := range clusterChanges {
primaryChanges[key] = value
}
Expand All @@ -979,7 +980,7 @@ func resourceNetworkDeviceUpdate(ctx context.Context, d *schema.ResourceData, m
}
var secondaryChanges map[string]interface{}
if v, ok := d.GetOk(neDeviceSchemaNames["RedundantUUID"]); ok {
secondaryChanges = getResourceDataListElementChanges(supportedChanges, neDeviceSchemaNames["Secondary"], 0, d)
secondaryChanges = equinix_schema.GetResourceDataListElementChanges(supportedChanges, neDeviceSchemaNames["Secondary"], 0, d)
secondaryUpdateReq := client.NewDeviceUpdateRequest(v.(string))
if err := fillNetworkDeviceUpdateRequest(secondaryUpdateReq, secondaryChanges).Execute(); err != nil {
return diag.FromErr(err)
Expand Down
14 changes: 13 additions & 1 deletion equinix/resource_network_device_link.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/equinix/terraform-provider-equinix/internal/config"
equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors"
"github.com/equinix/terraform-provider-equinix/internal/hashcode"
equinix_schema "github.com/equinix/terraform-provider-equinix/internal/schema"
equinix_validation "github.com/equinix/terraform-provider-equinix/internal/validation"

"github.com/equinix/ne-go"
Expand Down Expand Up @@ -274,7 +275,7 @@ func resourceNetworkDeviceLinkUpdate(ctx context.Context, d *schema.ResourceData
client := m.(*config.Config).Ne
m.(*config.Config).AddModuleToNEUserAgent(&client, d)
var diags diag.Diagnostics
changes := getResourceDataChangedKeys([]string{
changes := equinix_schema.GetResourceDataChangedKeys([]string{
networkDeviceLinkSchemaNames["Name"], networkDeviceLinkSchemaNames["Subnet"],
networkDeviceLinkSchemaNames["Devices"], networkDeviceLinkSchemaNames["Links"],
}, d)
Expand Down Expand Up @@ -518,3 +519,14 @@ func networkDeviceLinkConnectionKey(v interface{}) string {
func networkDeviceLinkConnectionHash(v interface{}) int {
return hashcode.String(networkDeviceLinkConnectionKey(v))
}

func schemaSetToMap(set *schema.Set) map[int]interface{} {
transformed := make(map[int]interface{})
if set != nil {
list := set.List()
for i := range list {
transformed[set.F(list[i])] = list[i]
}
}
return transformed
}
46 changes: 46 additions & 0 deletions internal/schema/resourcedata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package schema

import "reflect"

// resourceDataProvider provies interface to schema.ResourceData
// for convenient mocking purposes
type resourceDataProvider interface {
Get(key string) interface{}
GetOk(key string) (interface{}, bool)
HasChange(key string) bool
GetChange(key string) (interface{}, interface{})
}

func getMapChangedKeys(keys []string, old, new map[string]interface{}) map[string]interface{} {
changed := make(map[string]interface{})
for _, key := range keys {
if !reflect.DeepEqual(old[key], new[key]) {
changed[key] = new[key]
}
}
return changed
}

func GetResourceDataChangedKeys(keys []string, d resourceDataProvider) map[string]interface{} {
changed := make(map[string]interface{})
for _, key := range keys {
if v := d.Get(key); v != nil && d.HasChange(key) {
changed[key] = v
}
}
return changed
}

func GetResourceDataListElementChanges(keys []string, listKeyName string, listIndex int, d resourceDataProvider) map[string]interface{} {
changed := make(map[string]interface{})
if !d.HasChange(listKeyName) {
return changed
}
old, new := d.GetChange(listKeyName)
oldList := old.([]interface{})
newList := new.([]interface{})
if len(oldList) < listIndex || len(newList) < listIndex {
return changed
}
return getMapChangedKeys(keys, oldList[listIndex].(map[string]interface{}), newList[listIndex].(map[string]interface{}))
}
Loading
Loading