Skip to content

Commit 7938d06

Browse files
committed
komega: add unstructured support to EqualObject
1 parent 25e9b08 commit 7938d06

File tree

2 files changed

+71
-83
lines changed

2 files changed

+71
-83
lines changed

pkg/envtest/komega/equalobject.go

Lines changed: 55 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package komega
1717
import (
1818
"fmt"
1919
"reflect"
20-
"strconv"
2120
"strings"
2221

2322
"github.com/google/go-cmp/cmp"
@@ -33,15 +32,15 @@ var (
3332
// IgnoreAutogeneratedMetadata contains the paths for all the metadata fields that are commonly set by the
3433
// client and APIServer. This is used as a MatchOption for situations when only user-provided metadata is relevant.
3534
IgnoreAutogeneratedMetadata = IgnorePaths{
36-
{"ObjectMeta", "UID"},
37-
{"ObjectMeta", "Generation"},
38-
{"ObjectMeta", "CreationTimestamp"},
39-
{"ObjectMeta", "ResourceVersion"},
40-
{"ObjectMeta", "ManagedFields"},
41-
{"ObjectMeta", "DeletionGracePeriodSeconds"},
42-
{"ObjectMeta", "DeletionTimestamp"},
43-
{"ObjectMeta", "SelfLink"},
44-
{"ObjectMeta", "GenerateName"},
35+
"metadata.uid",
36+
"metadata.generation",
37+
"metadata.creationTimestamp",
38+
"metadata.resourceVersion",
39+
"metadata.managedFields",
40+
"metadata.deletionGracePeriodSeconds",
41+
"metadata.deletionTimestamp",
42+
"metadata.selfLink",
43+
"metadata.generateName",
4544
}
4645
)
4746

@@ -112,70 +111,59 @@ func (d diffPath) String() string {
112111
// diffReporter is a custom recorder for cmp.Diff which records all paths that are
113112
// different between two objects.
114113
type diffReporter struct {
115-
stack []cmp.PathStep
116-
path []string
117-
jsonPath []string
114+
stack []cmp.PathStep
118115

119116
diffPaths []diffPath
120117
}
121118

122119
func (r *diffReporter) PushStep(s cmp.PathStep) {
123120
r.stack = append(r.stack, s)
124-
if len(r.stack) <= 1 {
125-
return
126-
}
127-
switch s := s.(type) {
128-
case cmp.SliceIndex:
129-
r.path = append(r.path, strconv.Itoa(s.Key()))
130-
r.jsonPath = append(r.jsonPath, strconv.Itoa(s.Key()))
131-
case cmp.MapIndex:
132-
key := fmt.Sprintf("%v", s.Key())
133-
// if strings.ContainsAny(key, ".[]/\\") {
134-
// key = fmt.Sprintf("[%s]", key)
135-
// } else {
136-
// key = "." + key
137-
// }
138-
r.path = append(r.path, key)
139-
r.jsonPath = append(r.jsonPath, key)
140-
case cmp.StructField:
141-
field := r.stack[len(r.stack)-2].Type().Field(s.Index())
142-
jsonName := strings.Split(field.Tag.Get("json"), ",")[0]
143-
r.path = append(r.path, s.String()[1:])
144-
r.jsonPath = append(r.jsonPath, jsonName)
145-
}
146121
}
147122

148123
func (r *diffReporter) Report(res cmp.Result) {
149124
if !res.Equal() {
150-
r.diffPaths = append(r.diffPaths, diffPath{types: r.path, json: r.jsonPath})
125+
r.diffPaths = append(r.diffPaths, r.currPath())
151126
}
152127
}
153128

154-
// func (r *diffReporter) currPath() string {
155-
// p := []string{}
156-
// for _, s := range r.stack[1:] {
157-
// switch s := s.(type) {
158-
// case cmp.StructField, cmp.SliceIndex, cmp.MapIndex:
159-
// p = append(p, s.String())
160-
// }
161-
// }
162-
// return strings.Join(p, "")[1:]
163-
// }
129+
func (r *diffReporter) currPath() diffPath {
130+
p := diffPath{types: []string{""}, json: []string{""}}
131+
i := 0
132+
for si, s := range r.stack[1:] {
133+
switch s := s.(type) {
134+
case cmp.StructField:
135+
p.types = append(p.types, s.String()[1:])
136+
field := r.stack[si].Type().Field(s.Index())
137+
p.json = append(p.json, strings.Split(field.Tag.Get("json"), ",")[0])
138+
i++
139+
case cmp.SliceIndex:
140+
key := fmt.Sprintf("[%d]", s.Key())
141+
p.types[i] += key
142+
p.json[i] += key
143+
case cmp.MapIndex:
144+
key := fmt.Sprintf("%v", s.Key())
145+
if strings.ContainsAny(key, ".[]/\\") {
146+
key = fmt.Sprintf("[%s]", key)
147+
p.types[i] += key
148+
p.json[i] += key
149+
} else {
150+
p.types = append(p.types, key)
151+
p.json = append(p.json, key)
152+
i++
153+
}
154+
}
155+
}
156+
// empty strings were added as the first element, if they're still empty remove them again
157+
if len(p.json) > 0 && len(p.json[0]) == 0 {
158+
p.json = p.json[1:]
159+
p.types = p.types[1:]
160+
}
161+
fmt.Println(p)
162+
return p
163+
}
164164

165165
func (r *diffReporter) PopStep() {
166-
popped := r.stack[len(r.stack)-1]
167166
r.stack = r.stack[:len(r.stack)-1]
168-
if _, ok := popped.(cmp.Indirect); ok {
169-
return
170-
}
171-
if len(r.stack) <= 1 {
172-
return
173-
}
174-
switch popped.(type) {
175-
case cmp.SliceIndex, cmp.MapIndex, cmp.StructField:
176-
r.path = r.path[:len(r.path)-1]
177-
r.jsonPath = r.jsonPath[:len(r.jsonPath)-1]
178-
}
179167
}
180168

181169
// calculateDiff calculates the difference between two objects and returns the
@@ -210,7 +198,7 @@ func filterDiffPaths(opts EqualObjectOptions, paths []diffPath) []diffPath {
210198

211199
func matchesPath(path []string, prefix []string) bool {
212200
for i, p := range prefix {
213-
if i >= len(path) || p != path[i] {
201+
if i >= len(path) || !strings.HasPrefix(path[i], p) {
214202
return false
215203
}
216204
}
@@ -249,23 +237,22 @@ func (o *EqualObjectOptions) ApplyOptions(opts []EqualObjectOption) *EqualObject
249237
return o
250238
}
251239

252-
// func parsePath(path string) []string {
253-
// s := strings.Split(path, ".")
254-
// return s
255-
// }
256-
257240
// IgnorePaths instructs the Matcher to ignore given paths when computing a diff.
258-
type IgnorePaths [][]string
241+
type IgnorePaths []string
259242

260243
// ApplyToEqualObjectMatcher applies this configuration to the given MatchOptions.
261244
func (i IgnorePaths) ApplyToEqualObjectMatcher(opts *EqualObjectOptions) {
262-
opts.ignorePaths = append(opts.ignorePaths, i...)
245+
for _, p := range i {
246+
opts.ignorePaths = append(opts.ignorePaths, strings.Split(p, "."))
247+
}
263248
}
264249

265250
// MatchPaths instructs the Matcher to restrict its diff to the given paths. If empty the Matcher will look at all paths.
266-
type MatchPaths [][]string
251+
type MatchPaths []string
267252

268253
// ApplyToEqualObjectMatcher applies this configuration to the given MatchOptions.
269254
func (i MatchPaths) ApplyToEqualObjectMatcher(opts *EqualObjectOptions) {
270-
opts.matchPaths = append(opts.matchPaths, i...)
255+
for _, p := range i {
256+
opts.ignorePaths = append(opts.ignorePaths, strings.Split(p, "."))
257+
}
271258
}

pkg/envtest/komega/equalobject_test.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ func TestEqualObjectMatcher(t *testing.T) {
6969
result: true,
7070
opts: []EqualObjectOption{
7171
IgnorePaths{
72-
{"ObjectMeta", "Name"},
73-
{"ObjectMeta", "CreationTimestamp"},
74-
{"ObjectMeta", "Labels", "somelabel"},
75-
{"ObjectMeta", "OwnerReferences", "0", "Name"},
76-
{"Spec", "Template", "ObjectMeta"},
72+
"ObjectMeta.Name",
73+
"ObjectMeta.CreationTimestamp",
74+
"ObjectMeta.Labels.somelabel",
75+
"ObjectMeta.OwnerReferences[0].Name",
76+
"Spec.Template.ObjectMeta",
7777
},
7878
},
7979
},
@@ -100,11 +100,11 @@ func TestEqualObjectMatcher(t *testing.T) {
100100
result: true,
101101
opts: []EqualObjectOption{
102102
IgnorePaths{
103-
{"metadata", "name"},
104-
{"metadata", "creationTimestamp"},
105-
{"metadata", "labels", "somelabel"},
106-
{"metadata", "ownerReferences", "0", "name"},
107-
{"spec", "template", "metadata"},
103+
"metadata.name",
104+
"metadata.creationTimestamp",
105+
"metadata.labels.somelabel",
106+
"metadata.ownerReferences[0].name",
107+
"spec.template.metadata",
108108
},
109109
},
110110
},
@@ -125,7 +125,7 @@ func TestEqualObjectMatcher(t *testing.T) {
125125
result: true,
126126
opts: []EqualObjectOption{
127127
MatchPaths{
128-
{"ObjectMeta", "Name"},
128+
"ObjectMeta.Name",
129129
},
130130
},
131131
},
@@ -134,21 +134,23 @@ func TestEqualObjectMatcher(t *testing.T) {
134134
expected: &unstructured.Unstructured{
135135
Object: map[string]interface{}{
136136
"metadata": map[string]interface{}{
137-
"name": "something",
137+
"name": "something",
138+
"namespace": "test",
138139
},
139140
},
140141
},
141142
actual: &unstructured.Unstructured{
142143
Object: map[string]interface{}{
143144
"metadata": map[string]interface{}{
144-
"name": "somethingelse",
145+
"name": "somethingelse",
146+
"namespace": "test",
145147
},
146148
},
147149
},
148150
result: true,
149151
opts: []EqualObjectOption{
150152
IgnorePaths{
151-
{"metadata", "name"},
153+
"metadata.name",
152154
},
153155
},
154156
},
@@ -159,7 +161,6 @@ func TestEqualObjectMatcher(t *testing.T) {
159161
g := NewWithT(t)
160162
m := EqualObject(c.expected, c.opts...)
161163
g.Expect(m.Match(c.actual)).To(Equal(c.result))
162-
//fmt.Println(m.FailureMessage(&c.actual))
163164
})
164165
}
165166
}

0 commit comments

Comments
 (0)