1
16
17 package internal
18
19 import (
20 "fmt"
21 "reflect"
22 "testing"
23 "time"
24
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26
27 "sigs.k8s.io/yaml"
28 )
29
30
31
32 func TestHasFieldsType(t *testing.T) {
33 var unmarshaled []metav1.ManagedFieldsEntry
34 if err := yaml.Unmarshal([]byte(`- apiVersion: v1
35 fieldsType: FieldsV1
36 fieldsV1:
37 f:field: {}
38 manager: foo
39 operation: Apply
40 `), &unmarshaled); err != nil {
41 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
42 }
43 if _, err := DecodeManagedFields(unmarshaled); err != nil {
44 t.Fatalf("did not expect decoding error but got: %v", err)
45 }
46
47
48 if err := yaml.Unmarshal([]byte(`- apiVersion: v1
49 fieldsType: FieldsV2
50 fieldsV1:
51 f:field: {}
52 manager: foo
53 operation: Apply
54 `), &unmarshaled); err != nil {
55 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
56 }
57 if _, err := DecodeManagedFields(unmarshaled); err == nil {
58 t.Fatal("Expect decoding error but got none")
59 }
60
61
62 if err := yaml.Unmarshal([]byte(`- apiVersion: v1
63 fieldsV1:
64 f:field: {}
65 manager: foo
66 operation: Apply
67 `), &unmarshaled); err != nil {
68 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
69 }
70 if _, err := DecodeManagedFields(unmarshaled); err == nil {
71 t.Fatal("Expect decoding error but got none")
72 }
73 }
74
75
76
77 func TestHasAPIVersion(t *testing.T) {
78 var unmarshaled []metav1.ManagedFieldsEntry
79 if err := yaml.Unmarshal([]byte(`- apiVersion: v1
80 fieldsType: FieldsV1
81 fieldsV1:
82 f:field: {}
83 manager: foo
84 operation: Apply
85 `), &unmarshaled); err != nil {
86 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
87 }
88 if _, err := DecodeManagedFields(unmarshaled); err != nil {
89 t.Fatalf("did not expect decoding error but got: %v", err)
90 }
91
92
93 unmarshaled = nil
94 if err := yaml.Unmarshal([]byte(`- fieldsType: FieldsV1
95 fieldsV1:
96 f:field: {}
97 manager: foo
98 operation: Apply
99 `), &unmarshaled); err != nil {
100 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
101 }
102 if _, err := DecodeManagedFields(unmarshaled); err == nil {
103 t.Fatal("Expect decoding error but got none")
104 }
105 }
106
107
108
109 func TestHasOperation(t *testing.T) {
110 var unmarshaled []metav1.ManagedFieldsEntry
111 if err := yaml.Unmarshal([]byte(`- apiVersion: v1
112 fieldsType: FieldsV1
113 fieldsV1:
114 f:field: {}
115 manager: foo
116 operation: Apply
117 `), &unmarshaled); err != nil {
118 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
119 }
120 if _, err := DecodeManagedFields(unmarshaled); err != nil {
121 t.Fatalf("did not expect decoding error but got: %v", err)
122 }
123
124
125 if err := yaml.Unmarshal([]byte(`- apiVersion: v1
126 fieldsType: FieldsV1
127 fieldsV1:
128 f:field: {}
129 manager: foo
130 operation: Invalid
131 `), &unmarshaled); err != nil {
132 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
133 }
134 if _, err := DecodeManagedFields(unmarshaled); err == nil {
135 t.Fatal("Expect decoding error but got none")
136 }
137
138
139 unmarshaled = nil
140 if err := yaml.Unmarshal([]byte(`- apiVersion: v1
141 fieldsType: FieldsV1
142 fieldsV1:
143 f:field: {}
144 manager: foo
145 `), &unmarshaled); err != nil {
146 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
147 }
148 if _, err := DecodeManagedFields(unmarshaled); err == nil {
149 t.Fatal("Expect decoding error but got none")
150 }
151 }
152
153
154
155 func TestRoundTripManagedFields(t *testing.T) {
156 tests := []string{
157 `null
158 `,
159 `- apiVersion: v1
160 fieldsType: FieldsV1
161 fieldsV1:
162 v:3:
163 f:alsoPi: {}
164 v:3.1415:
165 f:pi: {}
166 v:false:
167 f:notTrue: {}
168 manager: foo
169 operation: Update
170 time: "2001-02-03T04:05:06Z"
171 - apiVersion: v1beta1
172 fieldsType: FieldsV1
173 fieldsV1:
174 i:5:
175 f:i: {}
176 manager: foo
177 operation: Update
178 time: "2011-12-13T14:15:16Z"
179 `,
180 `- apiVersion: v1
181 fieldsType: FieldsV1
182 fieldsV1:
183 f:spec:
184 f:containers:
185 k:{"name":"c"}:
186 f:image: {}
187 f:name: {}
188 manager: foo
189 operation: Apply
190 `,
191 `- apiVersion: v1
192 fieldsType: FieldsV1
193 fieldsV1:
194 f:apiVersion: {}
195 f:kind: {}
196 f:metadata:
197 f:labels:
198 f:app: {}
199 f:name: {}
200 f:spec:
201 f:replicas: {}
202 f:selector:
203 f:matchLabels:
204 f:app: {}
205 f:template:
206 f:medatada:
207 f:labels:
208 f:app: {}
209 f:spec:
210 f:containers:
211 k:{"name":"nginx"}:
212 .: {}
213 f:image: {}
214 f:name: {}
215 f:ports:
216 i:0:
217 f:containerPort: {}
218 manager: foo
219 operation: Update
220 `,
221 `- apiVersion: v1
222 fieldsType: FieldsV1
223 fieldsV1:
224 f:allowVolumeExpansion: {}
225 f:apiVersion: {}
226 f:kind: {}
227 f:metadata:
228 f:name: {}
229 f:parameters:
230 f:resturl: {}
231 f:restuser: {}
232 f:secretName: {}
233 f:secretNamespace: {}
234 f:provisioner: {}
235 manager: foo
236 operation: Apply
237 `,
238 `- apiVersion: v1
239 fieldsType: FieldsV1
240 fieldsV1:
241 f:apiVersion: {}
242 f:kind: {}
243 f:metadata:
244 f:name: {}
245 f:spec:
246 f:group: {}
247 f:names:
248 f:kind: {}
249 f:plural: {}
250 f:shortNames:
251 i:0: {}
252 f:singular: {}
253 f:scope: {}
254 f:versions:
255 k:{"name":"v1"}:
256 f:name: {}
257 f:served: {}
258 f:storage: {}
259 manager: foo
260 operation: Update
261 `,
262 `- apiVersion: v1
263 fieldsType: FieldsV1
264 fieldsV1:
265 f:spec:
266 f:replicas: {}
267 manager: foo
268 operation: Update
269 subresource: scale
270 `,
271 }
272
273 for _, test := range tests {
274 t.Run(test, func(t *testing.T) {
275 var unmarshaled []metav1.ManagedFieldsEntry
276 if err := yaml.Unmarshal([]byte(test), &unmarshaled); err != nil {
277 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
278 }
279 decoded, err := DecodeManagedFields(unmarshaled)
280 if err != nil {
281 t.Fatalf("did not expect decoding error but got: %v", err)
282 }
283 encoded, err := encodeManagedFields(decoded)
284 if err != nil {
285 t.Fatalf("did not expect encoding error but got: %v", err)
286 }
287 marshaled, err := yaml.Marshal(&encoded)
288 if err != nil {
289 t.Fatalf("did not expect yaml marshalling error but got: %v", err)
290 }
291 if !reflect.DeepEqual(string(marshaled), test) {
292 t.Fatalf("expected:\n%v\nbut got:\n%v", test, string(marshaled))
293 }
294 })
295 }
296 }
297
298 func TestBuildManagerIdentifier(t *testing.T) {
299 tests := []struct {
300 managedFieldsEntry string
301 expected string
302 }{
303 {
304 managedFieldsEntry: `
305 apiVersion: v1
306 fieldsV1:
307 f:apiVersion: {}
308 manager: foo
309 operation: Update
310 time: "2001-02-03T04:05:06Z"
311 `,
312 expected: "{\"manager\":\"foo\",\"operation\":\"Update\",\"apiVersion\":\"v1\"}",
313 },
314 {
315 managedFieldsEntry: `
316 apiVersion: v1
317 fieldsV1:
318 f:apiVersion: {}
319 manager: foo
320 operation: Apply
321 time: "2001-02-03T04:05:06Z"
322 `,
323 expected: "{\"manager\":\"foo\",\"operation\":\"Apply\"}",
324 },
325 {
326 managedFieldsEntry: `
327 apiVersion: v1
328 fieldsV1:
329 f:apiVersion: {}
330 manager: foo
331 operation: Apply
332 subresource: scale
333 time: "2001-02-03T04:05:06Z"
334 `,
335 expected: "{\"manager\":\"foo\",\"operation\":\"Apply\",\"subresource\":\"scale\"}",
336 },
337 }
338
339 for _, test := range tests {
340 t.Run(test.managedFieldsEntry, func(t *testing.T) {
341 var unmarshaled metav1.ManagedFieldsEntry
342 if err := yaml.Unmarshal([]byte(test.managedFieldsEntry), &unmarshaled); err != nil {
343 t.Fatalf("did not expect yaml unmarshalling error but got: %v", err)
344 }
345 decoded, err := BuildManagerIdentifier(&unmarshaled)
346 if err != nil {
347 t.Fatalf("did not expect decoding error but got: %v", err)
348 }
349 if !reflect.DeepEqual(decoded, test.expected) {
350 t.Fatalf("expected:\n%v\nbut got:\n%v", test.expected, decoded)
351 }
352 })
353 }
354 }
355
356 func TestSortEncodedManagedFields(t *testing.T) {
357 tests := []struct {
358 name string
359 managedFields []metav1.ManagedFieldsEntry
360 expected []metav1.ManagedFieldsEntry
361 }{
362 {
363 name: "empty",
364 managedFields: []metav1.ManagedFieldsEntry{},
365 expected: []metav1.ManagedFieldsEntry{},
366 },
367 {
368 name: "nil",
369 managedFields: nil,
370 expected: nil,
371 },
372 {
373 name: "remains untouched",
374 managedFields: []metav1.ManagedFieldsEntry{
375 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
376 {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
377 },
378 expected: []metav1.ManagedFieldsEntry{
379 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
380 {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
381 },
382 },
383 {
384 name: "manager without time first",
385 managedFields: []metav1.ManagedFieldsEntry{
386 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
387 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
388 },
389 expected: []metav1.ManagedFieldsEntry{
390 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
391 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
392 },
393 },
394 {
395 name: "manager without time first name last",
396 managedFields: []metav1.ManagedFieldsEntry{
397 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
398 {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
399 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
400 },
401 expected: []metav1.ManagedFieldsEntry{
402 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
403 {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
404 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
405 },
406 },
407 {
408 name: "apply first",
409 managedFields: []metav1.ManagedFieldsEntry{
410 {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
411 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
412 },
413 expected: []metav1.ManagedFieldsEntry{
414 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
415 {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
416 },
417 },
418 {
419 name: "newest last",
420 managedFields: []metav1.ManagedFieldsEntry{
421 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
422 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
423 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
424 {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
425 },
426 expected: []metav1.ManagedFieldsEntry{
427 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
428 {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
429 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
430 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
431 },
432 },
433 {
434 name: "manager last",
435 managedFields: []metav1.ManagedFieldsEntry{
436 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
437 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
438 {Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
439 {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
440 },
441 expected: []metav1.ManagedFieldsEntry{
442 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
443 {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
444 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
445 {Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
446 },
447 },
448 {
449 name: "manager sorted",
450 managedFields: []metav1.ManagedFieldsEntry{
451 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
452 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
453 {Manager: "g", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
454 {Manager: "f", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
455 {Manager: "i", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
456 {Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
457 {Manager: "h", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
458 {Manager: "e", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2003-01-01T01:00:00Z")},
459 {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
460 },
461 expected: []metav1.ManagedFieldsEntry{
462 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
463 {Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
464 {Manager: "g", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
465 {Manager: "h", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
466 {Manager: "i", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
467 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
468 {Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
469 {Manager: "f", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
470 {Manager: "e", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2003-01-01T01:00:00Z")},
471 },
472 },
473 {
474 name: "sort drops nanoseconds",
475 managedFields: []metav1.ManagedFieldsEntry{
476 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 1, time.UTC)}},
477 {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 2, time.UTC)}},
478 {Manager: "b", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 3, time.UTC)}},
479 },
480 expected: []metav1.ManagedFieldsEntry{
481 {Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 2, time.UTC)}},
482 {Manager: "b", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 3, time.UTC)}},
483 {Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: &metav1.Time{Time: time.Date(2000, time.January, 0, 0, 0, 0, 1, time.UTC)}},
484 },
485 },
486 {
487 name: "entries with subresource field",
488 managedFields: []metav1.ManagedFieldsEntry{
489 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Subresource: "status"},
490 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Subresource: "scale"},
491 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply},
492 },
493 expected: []metav1.ManagedFieldsEntry{
494 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply},
495 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Subresource: "scale"},
496 {Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Subresource: "status"},
497 },
498 },
499 }
500
501 for _, test := range tests {
502 t.Run(test.name, func(t *testing.T) {
503 sorted, err := sortEncodedManagedFields(test.managedFields)
504 if err != nil {
505 t.Fatalf("did not expect error when sorting but got: %v", err)
506 }
507 if !reflect.DeepEqual(sorted, test.expected) {
508 t.Fatalf("expected:\n%v\nbut got:\n%v", test.expected, sorted)
509 }
510 })
511 }
512 }
513
514 func parseTimeOrPanic(s string) *metav1.Time {
515 t, err := time.Parse(time.RFC3339, s)
516 if err != nil {
517 panic(fmt.Sprintf("failed to parse time %s, got: %v", s, err))
518 }
519 return &metav1.Time{Time: t.UTC()}
520 }
521
View as plain text