Skip to content

Commit

Permalink
fix pluginDeepEqual when integer value is decoded as float64
Browse files Browse the repository at this point in the history
cherry-picked from 1f7ad0d


From #196
  • Loading branch information
fffonion authored and hbagdi committed Nov 9, 2018
1 parent 37e7e60 commit fc359d0
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 8 deletions.
64 changes: 58 additions & 6 deletions internal/ingress/controller/kong.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package controller

import (
"bytes"
"encoding/json"
"fmt"
"net"
"net/http"
Expand All @@ -27,10 +28,9 @@ import (
"strings"
"time"

"github.com/imdario/mergo"

"github.com/fatih/structs"
"github.com/golang/glog"
"github.com/imdario/mergo"
kong "github.com/kong/kubernetes-ingress-controller/internal/apis/admin"
kongadminv1 "github.com/kong/kubernetes-ingress-controller/internal/apis/admin/v1"
configurationv1 "github.com/kong/kubernetes-ingress-controller/internal/apis/configuration/v1"
Expand Down Expand Up @@ -1291,17 +1291,69 @@ func deleteServiceUpstream(host string, client *kong.RestClient) error {
// the persisted state in the Kong database
// This is required because a plugin has defaults that could not exists in the CRD.
func pluginDeepEqual(config map[string]interface{}, kong *kongadminv1.Plugin) bool {
for k, v := range config {
kv, ok := kong.Config[k]
if !ok {
return pluginDeepEqualWrapper(config, kong.Config)
}

func pluginDeepEqualWrapper(config1 map[string]interface{}, config2 map[string]interface{}) bool {
return interfaceDeepEqual(config1, config2)
}

func interfaceDeepEqual(i1 interface{}, i2 interface{}) bool {
v1 := reflect.ValueOf(i1)
v2 := reflect.ValueOf(i2)

k1 := v1.Type().Kind()
k2 := v2.Type().Kind()
if k1 == k2 {
if k1 == reflect.Map {
return mapDeepEqual(v1, v2)
} else if k1 == reflect.Slice || k1 == reflect.Array {
return listUnorderedDeepEqual(v1, v2)
}
}
j1, e1 := json.Marshal(v1.Interface())
j2, e2 := json.Marshal(v2.Interface())
return e1 == nil && e2 == nil && string(j1) == string(j2)
}

func mapDeepEqual(m1 reflect.Value, m2 reflect.Value) bool {
keys1 := m1.MapKeys()
for _, k := range keys1 {
v2 := m2.MapIndex(k)
if !v2.IsValid() { // k not found in m2
return false
}
v1 := m1.MapIndex(k)

if !reflect.DeepEqual(v, kv) {
if v1.IsValid() && !interfaceDeepEqual(v1.Interface(), v2.Interface()) {
return false
}
}
return true
}

func listUnorderedDeepEqual(l1 reflect.Value, l2 reflect.Value) bool {
length := l1.Len()
if length != l2.Len() {
return false
}
for i := 0; i < length; i++ {
v1 := l1.Index(i)
if !v1.IsValid() {
return false // this shouldn't happen
}
found := false
for j := 0; j < length; j++ {
v2 := l2.Index(j)
if v2.IsValid() && interfaceDeepEqual(v1.Interface(), v2.Interface()) {
found = true
break
}
}
if !found {
return false
}
}
return true
}

Expand Down
103 changes: 101 additions & 2 deletions internal/ingress/controller/kong_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ func TestPluginDeepEqual(t *testing.T) {
t.Errorf("Comparing maps with nested map failed")
}

equal = pluginDeepEqual(map[string]interface{}{
"key1": 1,
"key2": 2,
"key3": 8,
}, &kongadminv1.Plugin{Config: map[string]interface{}{
"key1": 1.0,
"key2": 2.0,
"key3": 8,
}})
if !equal {
t.Errorf("Comparing maps with numeric values in different type failed")
}

equal = pluginDeepEqual(map[string]interface{}{
"key1": map[string]string{},
"key2": "value2",
Expand Down Expand Up @@ -116,8 +129,42 @@ func TestPluginDeepEqual(t *testing.T) {
"arr2", "arr3", "arr1",
},
}})
if equal {
t.Errorf("Comparing maps with nested array with different order failed")
if !equal {
t.Errorf("Comparing maps with nested string array with different order failed")
}

equal = pluginDeepEqual(map[string]interface{}{
"key1": [3]int{
1, 2, 3,
},
"key2": "value2",
"key3": "value3",
}, &kongadminv1.Plugin{Config: map[string]interface{}{
"key2": "value2",
"key3": "value3",
"key1": [3]float64{
1.0, 2.0, 3.0,
},
}})
if !equal {
t.Errorf("Comparing maps with nested numeric value array failed")
}

equal = pluginDeepEqual(map[string]interface{}{
"key1": []interface{}{
1, map[string]string{"1": "2"}, "3",
},
"key2": "value2",
"key3": "value3",
}, &kongadminv1.Plugin{Config: map[string]interface{}{
"key2": "value2",
"key3": "value3",
"key1": []interface{}{
1.0, "3", map[string]string{"1": "2"},
},
}})
if !equal {
t.Errorf("Comparing maps with interface value array failed")
}

equal = pluginDeepEqual(map[string]interface{}{
Expand Down Expand Up @@ -165,4 +212,56 @@ func TestPluginDeepEqual(t *testing.T) {
if equal {
t.Errorf("Comparing maps with unmatched keys failed")
}

equal = pluginDeepEqual(map[string]interface{}{
"key1": map[string]string{
"nestedkey1": "nestedvalue1",
"nestedkey2": "nestedvalue2",
},
"key2": "value2",
"key3": "value3",
}, &kongadminv1.Plugin{Config: map[string]interface{}{
"key3": "value3",
"key1": map[string]string{
"nestedkey1": "nestedvalue1",
"nestedkey2": "nestedvalue3",
},
"key2": "value2",
}})
if equal {
t.Errorf("Comparing maps with unmatched keys in nested structure failed")
}

equal = pluginDeepEqual(map[string]interface{}{
"key2": "value2",
"key1": map[string]string{
"nestedkey1": "nestedvalue1",
},
}, &kongadminv1.Plugin{Config: map[string]interface{}{
"key2": "value2",
"key1": map[string]string{
"nestedkey1": "nestedvalue1",
},
"default3": "value3",
}})
if !equal {
t.Errorf("Comparing maps with default configs failed")
}

equal = pluginDeepEqual(map[string]interface{}{
"key2": "value2",
"key1": map[string]string{
"nestedkey1": "nestedvalue1",
},
}, &kongadminv1.Plugin{Config: map[string]interface{}{
"key2": "value2",
"key1": map[string]string{
"nestedkey1": "nestedvalue1",
"defaultnested2": "nestedvalue2",
},
"default3": "value3",
}})
if !equal {
t.Errorf("Comparing maps with nested default configs failed")
}
}

0 comments on commit fc359d0

Please sign in to comment.