Skip to content

Commit 9481f13

Browse files
authored
add mergo transformer to handle resource.Quantity type (#45)
1 parent 10978ca commit 9481f13

2 files changed

Lines changed: 125 additions & 12 deletions

File tree

utils/mergo/transformers.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import (
44
"reflect"
55

66
"dario.cat/mergo"
7+
"k8s.io/apimachinery/pkg/api/resource"
78
)
89

910
var _ mergo.Transformers = BoolPtrTransformer{}
1011
var _ mergo.Transformers = CombinedTransformer{}
12+
var _ mergo.Transformers = ResourceQuantityTransformer{}
1113

1214
type CombinedTransformer struct {
1315
Transformers []mergo.Transformers
@@ -35,3 +37,22 @@ func (t BoolPtrTransformer) Transformer(typ reflect.Type) func(dst, src reflect.
3537
}
3638
return nil
3739
}
40+
41+
// ResourceQuantityTransformer is a dario.cat/mergo Transformers implementation that handles merging of k8s.io/apimachinery/pkg/api/resource Quantity types
42+
type ResourceQuantityTransformer struct {
43+
}
44+
45+
func (t ResourceQuantityTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
46+
if typ == reflect.TypeOf(resource.Quantity{}) {
47+
return func(dst, src reflect.Value) error {
48+
if dst.CanSet() {
49+
srcVal := (src.Interface()).(resource.Quantity)
50+
if !srcVal.IsZero() {
51+
dst.Set(src)
52+
}
53+
}
54+
return nil
55+
}
56+
}
57+
return nil
58+
}

utils/mergo/transformers_test.go

Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"dario.cat/mergo"
77
"github.com/stretchr/testify/assert"
88
"github.com/stretchr/testify/require"
9+
"k8s.io/apimachinery/pkg/api/resource"
910
)
1011

1112
func Test_BoolPtrTransformer(t *testing.T) {
@@ -15,24 +16,115 @@ func Test_BoolPtrTransformer(t *testing.T) {
1516
}
1617
boolPtr := func(v bool) *bool { return &v }
1718

18-
scenarios := []struct {
19-
name string
19+
tests := map[string]struct {
2020
dst testBool
2121
src testBool
2222
expected testBool
2323
}{
24-
{name: "use value from src #1", dst: testBool{V: boolPtr(true)}, src: testBool{V: boolPtr(false)}, expected: testBool{V: boolPtr(false)}},
25-
{name: "use value from src #2", dst: testBool{V: boolPtr(false)}, src: testBool{V: boolPtr(true)}, expected: testBool{V: boolPtr(true)}},
26-
{name: "use value from src #3", dst: testBool{}, src: testBool{V: boolPtr(false)}, expected: testBool{V: boolPtr(false)}},
27-
{name: "use value from src #4", dst: testBool{}, src: testBool{V: boolPtr(true)}, expected: testBool{V: boolPtr(true)}},
28-
{name: "use value from dst #1", dst: testBool{V: boolPtr(true)}, src: testBool{}, expected: testBool{V: boolPtr(true)}},
29-
{name: "use value from dst #2", dst: testBool{V: boolPtr(false)}, src: testBool{}, expected: testBool{V: boolPtr(false)}},
24+
"use value from src #1": {dst: testBool{V: boolPtr(true)}, src: testBool{V: boolPtr(false)}, expected: testBool{V: boolPtr(false)}},
25+
"use value from src #2": {dst: testBool{V: boolPtr(false)}, src: testBool{V: boolPtr(true)}, expected: testBool{V: boolPtr(true)}},
26+
"use value from src #3": {dst: testBool{}, src: testBool{V: boolPtr(false)}, expected: testBool{V: boolPtr(false)}},
27+
"use value from src #4": {dst: testBool{}, src: testBool{V: boolPtr(true)}, expected: testBool{V: boolPtr(true)}},
28+
"use value from dst #1": {dst: testBool{V: boolPtr(true)}, src: testBool{}, expected: testBool{V: boolPtr(true)}},
29+
"use value from dst #2": {dst: testBool{V: boolPtr(false)}, src: testBool{}, expected: testBool{V: boolPtr(false)}},
3030
}
3131

32-
for _, scenario := range scenarios {
33-
err := mergo.Merge(&scenario.dst, &scenario.src, mergo.WithOverride, mergo.WithTransformers(BoolPtrTransformer{}))
34-
require.NoError(t, err, scenario.name)
35-
assert.Equal(t, scenario.expected, scenario.dst, scenario.name)
32+
for testName, test := range tests {
33+
t.Run(testName, func(t *testing.T) {
34+
err := mergo.Merge(&test.dst, &test.src, mergo.WithOverride, mergo.WithTransformers(BoolPtrTransformer{}))
35+
require.NoError(t, err)
36+
assert.Equal(t, test.expected, test.dst)
37+
})
38+
}
39+
}
40+
41+
func Test_ResourceQuantityTransformer_ValueType(t *testing.T) {
42+
type testObj struct {
43+
V resource.Quantity
44+
}
45+
46+
tests := map[string]struct {
47+
dst testObj
48+
src testObj
49+
expected testObj
50+
}{
51+
"dst empty, src set, expect src": {dst: testObj{V: resource.Quantity{}}, src: testObj{V: resource.MustParse("2M")}, expected: testObj{V: resource.MustParse("2M")}},
52+
"dst set, src set, expect src": {dst: testObj{V: resource.MustParse("1M")}, src: testObj{V: resource.MustParse("2M")}, expected: testObj{V: resource.MustParse("2M")}},
53+
"dst set, src empty, expect src": {dst: testObj{V: resource.MustParse("1M")}, src: testObj{V: resource.Quantity{}}, expected: testObj{V: resource.MustParse("1M")}},
54+
"all empty, expect empty": {dst: testObj{V: resource.Quantity{}}, src: testObj{V: resource.Quantity{}}, expected: testObj{V: resource.Quantity{}}},
3655
}
3756

57+
for testName, test := range tests {
58+
t.Run(testName, func(t *testing.T) {
59+
err := mergo.Merge(&test.dst, &test.src, mergo.WithOverride, mergo.WithTransformers(ResourceQuantityTransformer{}))
60+
require.NoError(t, err)
61+
assert.Equal(t, test.expected, test.dst)
62+
})
63+
}
64+
}
65+
66+
func Test_ResourceQuantityTransformer_PointerType(t *testing.T) {
67+
type testObj struct {
68+
V *resource.Quantity
69+
}
70+
71+
tests := map[string]struct {
72+
dst testObj
73+
src testObj
74+
expected testObj
75+
}{
76+
"dst empty, src set, expect src": {
77+
dst: testObj{V: &resource.Quantity{}},
78+
src: testObj{V: resource.NewMilliQuantity(2, resource.DecimalSI)},
79+
expected: testObj{V: resource.NewMilliQuantity(2, resource.DecimalSI)},
80+
},
81+
"dst set, src empty, expect dst": {
82+
dst: testObj{V: resource.NewMilliQuantity(1, resource.DecimalSI)},
83+
src: testObj{V: &resource.Quantity{}},
84+
expected: testObj{V: resource.NewMilliQuantity(1, resource.DecimalSI)},
85+
},
86+
"dst set, src set, expect src": {
87+
dst: testObj{V: resource.NewMilliQuantity(1, resource.DecimalSI)},
88+
src: testObj{V: resource.NewMilliQuantity(2, resource.DecimalSI)},
89+
expected: testObj{V: resource.NewMilliQuantity(2, resource.DecimalSI)},
90+
},
91+
"dst nil, src set, expect src": {
92+
dst: testObj{V: nil},
93+
src: testObj{V: resource.NewMilliQuantity(2, resource.DecimalSI)},
94+
expected: testObj{V: resource.NewMilliQuantity(2, resource.DecimalSI)},
95+
},
96+
"dst set, src nil, expect dst": {
97+
dst: testObj{V: resource.NewMilliQuantity(1, resource.DecimalSI)},
98+
src: testObj{V: nil},
99+
expected: testObj{V: resource.NewMilliQuantity(1, resource.DecimalSI)},
100+
},
101+
"dst nil, src empty, expect empty": {
102+
dst: testObj{V: nil},
103+
src: testObj{V: &resource.Quantity{}},
104+
expected: testObj{V: &resource.Quantity{}},
105+
},
106+
"dst empty, src nil, expect empty": {
107+
dst: testObj{V: &resource.Quantity{}},
108+
src: testObj{V: nil},
109+
expected: testObj{V: &resource.Quantity{}},
110+
},
111+
"all empty, expect empty": {
112+
dst: testObj{V: &resource.Quantity{}},
113+
src: testObj{V: &resource.Quantity{}},
114+
expected: testObj{V: &resource.Quantity{}},
115+
},
116+
"all nil, expect nil": {
117+
dst: testObj{V: nil},
118+
src: testObj{V: nil},
119+
expected: testObj{V: nil},
120+
},
121+
}
122+
123+
for testName, test := range tests {
124+
t.Run(testName, func(t *testing.T) {
125+
err := mergo.Merge(&test.dst, &test.src, mergo.WithOverride, mergo.WithTransformers(ResourceQuantityTransformer{}))
126+
require.NoError(t, err)
127+
assert.Equal(t, test.expected, test.dst)
128+
})
129+
}
38130
}

0 commit comments

Comments
 (0)