1
16
17 package managedfields
18
19 import (
20 "reflect"
21 "testing"
22 "time"
23
24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 "k8s.io/apimachinery/pkg/runtime/schema"
26 "sigs.k8s.io/structured-merge-diff/v4/fieldpath"
27 )
28
29 func TestTransformManagedFieldsToSubresource(t *testing.T) {
30 testTime, _ := time.ParseInLocation("2006-Jan-02", "2013-Feb-03", time.Local)
31 managedFieldTime := metav1.NewTime(testTime)
32
33 tests := []struct {
34 desc string
35 input []metav1.ManagedFieldsEntry
36 expected []metav1.ManagedFieldsEntry
37 }{
38 {
39 desc: "filter one entry and transform it into a subresource entry",
40 input: []metav1.ManagedFieldsEntry{
41 {
42 Manager: "manager-1",
43 Operation: metav1.ManagedFieldsOperationApply,
44 APIVersion: "apps/v1",
45 FieldsType: "FieldsV1",
46 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:another-field":{}}}`)},
47 },
48 {
49 Manager: "manager-2",
50 Operation: metav1.ManagedFieldsOperationApply,
51 APIVersion: "apps/v1",
52 FieldsType: "FieldsV1",
53 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
54 Time: &managedFieldTime,
55 },
56 },
57 expected: []metav1.ManagedFieldsEntry{
58 {
59 Manager: "manager-2",
60 Operation: metav1.ManagedFieldsOperationApply,
61 APIVersion: "autoscaling/v1",
62 FieldsType: "FieldsV1",
63 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
64 Time: &managedFieldTime,
65 },
66 },
67 },
68 {
69 desc: "transform all entries",
70 input: []metav1.ManagedFieldsEntry{
71 {
72 Manager: "manager-1",
73 Operation: metav1.ManagedFieldsOperationApply,
74 APIVersion: "apps/v1",
75 FieldsType: "FieldsV1",
76 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
77 },
78 {
79 Manager: "manager-2",
80 Operation: metav1.ManagedFieldsOperationApply,
81 APIVersion: "apps/v1",
82 FieldsType: "FieldsV1",
83 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
84 },
85 {
86 Manager: "manager-3",
87 Operation: metav1.ManagedFieldsOperationApply,
88 APIVersion: "apps/v1",
89 FieldsType: "FieldsV1",
90 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
91 Subresource: "scale",
92 },
93 },
94 expected: []metav1.ManagedFieldsEntry{
95 {
96 Manager: "manager-1",
97 Operation: metav1.ManagedFieldsOperationApply,
98 APIVersion: "autoscaling/v1",
99 FieldsType: "FieldsV1",
100 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
101 },
102 {
103 Manager: "manager-2",
104 Operation: metav1.ManagedFieldsOperationApply,
105 APIVersion: "autoscaling/v1",
106 FieldsType: "FieldsV1",
107 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
108 },
109 {
110 Manager: "manager-3",
111 Operation: metav1.ManagedFieldsOperationApply,
112 APIVersion: "autoscaling/v1",
113 FieldsType: "FieldsV1",
114 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
115 Subresource: "scale",
116 },
117 },
118 },
119 {
120 desc: "drops fields if the api version is unknown",
121 input: []metav1.ManagedFieldsEntry{
122 {
123 Manager: "manager-1",
124 Operation: metav1.ManagedFieldsOperationApply,
125 APIVersion: "apps/v10",
126 FieldsType: "FieldsV1",
127 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
128 },
129 },
130 expected: nil,
131 },
132 }
133
134 for _, test := range tests {
135 handler := NewScaleHandler(
136 test.input,
137 schema.GroupVersion{Group: "apps", Version: "v1"},
138 defaultMappings(),
139 )
140 subresourceEntries, err := handler.ToSubresource()
141 if err != nil {
142 t.Fatalf("test %q - expected no error but got %v", test.desc, err)
143 }
144
145 if !reflect.DeepEqual(subresourceEntries, test.expected) {
146 t.Fatalf("test %q - expected output to be:\n%v\n\nbut got:\n%v", test.desc, test.expected, subresourceEntries)
147 }
148 }
149 }
150
151 func TestTransformingManagedFieldsToParent(t *testing.T) {
152 tests := []struct {
153 desc string
154 parent []metav1.ManagedFieldsEntry
155 subresource []metav1.ManagedFieldsEntry
156 expected []metav1.ManagedFieldsEntry
157 }{
158 {
159 desc: "different-managers: apply -> update",
160 parent: []metav1.ManagedFieldsEntry{
161 {
162 Manager: "test",
163 Operation: metav1.ManagedFieldsOperationApply,
164 APIVersion: "apps/v1",
165 FieldsType: "FieldsV1",
166 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
167 },
168 },
169 subresource: []metav1.ManagedFieldsEntry{
170 {
171 Manager: "scale",
172 Operation: metav1.ManagedFieldsOperationUpdate,
173 APIVersion: "autoscaling/v1",
174 FieldsType: "FieldsV1",
175 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
176 Subresource: "scale",
177 },
178 },
179 expected: []metav1.ManagedFieldsEntry{
180 {
181 Manager: "test",
182 Operation: metav1.ManagedFieldsOperationApply,
183 APIVersion: "apps/v1",
184 FieldsType: "FieldsV1",
185 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
186 },
187 {
188 Manager: "scale",
189 Operation: metav1.ManagedFieldsOperationUpdate,
190 APIVersion: "apps/v1",
191 FieldsType: "FieldsV1",
192 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
193 Subresource: "scale",
194 },
195 },
196 },
197 {
198 desc: "different-managers: apply -> apply",
199 parent: []metav1.ManagedFieldsEntry{
200 {
201 Manager: "test",
202 Operation: metav1.ManagedFieldsOperationApply,
203 APIVersion: "apps/v1",
204 FieldsType: "FieldsV1",
205 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
206 },
207 },
208 subresource: []metav1.ManagedFieldsEntry{
209 {
210 Manager: "scale",
211 Operation: metav1.ManagedFieldsOperationApply,
212 APIVersion: "autoscaling/v1",
213 FieldsType: "FieldsV1",
214 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
215 Subresource: "scale",
216 },
217 },
218 expected: []metav1.ManagedFieldsEntry{
219 {
220 Manager: "scale",
221 Operation: metav1.ManagedFieldsOperationApply,
222 APIVersion: "apps/v1",
223 FieldsType: "FieldsV1",
224 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
225 Subresource: "scale",
226 },
227 {
228 Manager: "test",
229 Operation: metav1.ManagedFieldsOperationApply,
230 APIVersion: "apps/v1",
231 FieldsType: "FieldsV1",
232 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
233 },
234 },
235 },
236 {
237 desc: "different-managers: update -> update",
238 parent: []metav1.ManagedFieldsEntry{
239 {
240 Manager: "test",
241 Operation: metav1.ManagedFieldsOperationUpdate,
242 APIVersion: "apps/v1",
243 FieldsType: "FieldsV1",
244 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
245 },
246 },
247 subresource: []metav1.ManagedFieldsEntry{
248 {
249 Manager: "scale",
250 Operation: metav1.ManagedFieldsOperationUpdate,
251 APIVersion: "autoscaling/v1",
252 FieldsType: "FieldsV1",
253 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
254 Subresource: "scale",
255 },
256 },
257 expected: []metav1.ManagedFieldsEntry{
258 {
259 Manager: "scale",
260 Operation: metav1.ManagedFieldsOperationUpdate,
261 APIVersion: "apps/v1",
262 FieldsType: "FieldsV1",
263 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
264 Subresource: "scale",
265 },
266 {
267 Manager: "test",
268 Operation: metav1.ManagedFieldsOperationUpdate,
269 APIVersion: "apps/v1",
270 FieldsType: "FieldsV1",
271 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
272 },
273 },
274 },
275 {
276 desc: "different-managers: update -> apply",
277 parent: []metav1.ManagedFieldsEntry{
278 {
279 Manager: "test",
280 Operation: metav1.ManagedFieldsOperationUpdate,
281 APIVersion: "apps/v1",
282 FieldsType: "FieldsV1",
283 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
284 },
285 },
286 subresource: []metav1.ManagedFieldsEntry{
287 {
288 Manager: "scale",
289 Operation: metav1.ManagedFieldsOperationApply,
290 APIVersion: "autoscaling/v1",
291 FieldsType: "FieldsV1",
292 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
293 Subresource: "scale",
294 },
295 },
296 expected: []metav1.ManagedFieldsEntry{
297 {
298 Manager: "scale",
299 Operation: metav1.ManagedFieldsOperationApply,
300 APIVersion: "apps/v1",
301 FieldsType: "FieldsV1",
302 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
303 Subresource: "scale",
304 },
305 {
306 Manager: "test",
307 Operation: metav1.ManagedFieldsOperationUpdate,
308 APIVersion: "apps/v1",
309 FieldsType: "FieldsV1",
310 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
311 },
312 },
313 },
314 {
315 desc: "same manager: apply -> apply",
316 parent: []metav1.ManagedFieldsEntry{
317 {
318 Manager: "test",
319 Operation: metav1.ManagedFieldsOperationApply,
320 APIVersion: "apps/v1",
321 FieldsType: "FieldsV1",
322 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
323 },
324 },
325 subresource: []metav1.ManagedFieldsEntry{
326 {
327 Manager: "test",
328 Operation: metav1.ManagedFieldsOperationApply,
329 APIVersion: "autoscaling/v1",
330 FieldsType: "FieldsV1",
331 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
332 Subresource: "scale",
333 },
334 },
335 expected: []metav1.ManagedFieldsEntry{
336 {
337 Manager: "test",
338 Operation: metav1.ManagedFieldsOperationApply,
339 APIVersion: "apps/v1",
340 FieldsType: "FieldsV1",
341 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
342 },
343 {
344 Manager: "test",
345 Operation: metav1.ManagedFieldsOperationApply,
346 APIVersion: "apps/v1",
347 FieldsType: "FieldsV1",
348 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
349 Subresource: "scale",
350 },
351 },
352 },
353 {
354 desc: "same manager: update -> update",
355 parent: []metav1.ManagedFieldsEntry{
356 {
357 Manager: "test",
358 Operation: metav1.ManagedFieldsOperationUpdate,
359 APIVersion: "apps/v1",
360 FieldsType: "FieldsV1",
361 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
362 },
363 },
364 subresource: []metav1.ManagedFieldsEntry{
365 {
366 Manager: "test",
367 Operation: metav1.ManagedFieldsOperationUpdate,
368 APIVersion: "autoscaling/v1",
369 FieldsType: "FieldsV1",
370 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
371 Subresource: "scale",
372 },
373 },
374 expected: []metav1.ManagedFieldsEntry{
375 {
376 Manager: "test",
377 Operation: metav1.ManagedFieldsOperationUpdate,
378 APIVersion: "apps/v1",
379 FieldsType: "FieldsV1",
380 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
381 },
382 {
383 Manager: "test",
384 Operation: metav1.ManagedFieldsOperationUpdate,
385 APIVersion: "apps/v1",
386 FieldsType: "FieldsV1",
387 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
388 Subresource: "scale",
389 },
390 },
391 },
392 {
393 desc: "same manager: update -> apply",
394 parent: []metav1.ManagedFieldsEntry{
395 {
396 Manager: "test",
397 Operation: metav1.ManagedFieldsOperationUpdate,
398 APIVersion: "apps/v1",
399 FieldsType: "FieldsV1",
400 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
401 },
402 },
403 subresource: []metav1.ManagedFieldsEntry{
404 {
405 Manager: "test",
406 Operation: metav1.ManagedFieldsOperationApply,
407 APIVersion: "autoscaling/v1",
408 FieldsType: "FieldsV1",
409 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
410 Subresource: "scale",
411 },
412 },
413 expected: []metav1.ManagedFieldsEntry{
414 {
415 Manager: "test",
416 Operation: metav1.ManagedFieldsOperationApply,
417 APIVersion: "apps/v1",
418 FieldsType: "FieldsV1",
419 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
420 Subresource: "scale",
421 },
422 {
423 Manager: "test",
424 Operation: metav1.ManagedFieldsOperationUpdate,
425 APIVersion: "apps/v1",
426 FieldsType: "FieldsV1",
427 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
428 },
429 },
430 },
431 {
432 desc: "same manager: apply -> update",
433 parent: []metav1.ManagedFieldsEntry{
434 {
435 Manager: "test",
436 Operation: metav1.ManagedFieldsOperationApply,
437 APIVersion: "apps/v1",
438 FieldsType: "FieldsV1",
439 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
440 },
441 },
442 subresource: []metav1.ManagedFieldsEntry{
443 {
444 Manager: "test",
445 Operation: metav1.ManagedFieldsOperationUpdate,
446 APIVersion: "autoscaling/v1",
447 FieldsType: "FieldsV1",
448 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
449 Subresource: "scale",
450 },
451 },
452 expected: []metav1.ManagedFieldsEntry{
453 {
454 Manager: "test",
455 Operation: metav1.ManagedFieldsOperationApply,
456 APIVersion: "apps/v1",
457 FieldsType: "FieldsV1",
458 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
459 },
460 {
461 Manager: "test",
462 Operation: metav1.ManagedFieldsOperationUpdate,
463 APIVersion: "apps/v1",
464 FieldsType: "FieldsV1",
465 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
466 Subresource: "scale",
467 },
468 },
469 },
470 {
471 desc: "subresource doesn't own the path anymore",
472 parent: []metav1.ManagedFieldsEntry{
473 {
474 Manager: "test",
475 Operation: metav1.ManagedFieldsOperationApply,
476 APIVersion: "apps/v1",
477 FieldsType: "FieldsV1",
478 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
479 },
480 },
481 subresource: []metav1.ManagedFieldsEntry{
482 {
483 Manager: "scale",
484 Operation: metav1.ManagedFieldsOperationUpdate,
485 APIVersion: "autoscaling/v1",
486 FieldsType: "FieldsV1",
487 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:status":{"f:replicas":{}}}`)},
488 Subresource: "scale",
489 },
490 },
491 expected: []metav1.ManagedFieldsEntry{
492 {
493 Manager: "test",
494 Operation: metav1.ManagedFieldsOperationApply,
495 APIVersion: "apps/v1",
496 FieldsType: "FieldsV1",
497 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
498 },
499 },
500 },
501 {
502 desc: "Subresource steals all the fields of the parent resource",
503 parent: []metav1.ManagedFieldsEntry{
504 {
505 Manager: "test",
506 Operation: metav1.ManagedFieldsOperationApply,
507 APIVersion: "apps/v1",
508 FieldsType: "FieldsV1",
509 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
510 },
511 },
512 subresource: []metav1.ManagedFieldsEntry{
513 {
514 Manager: "scale",
515 Operation: metav1.ManagedFieldsOperationUpdate,
516 APIVersion: "autoscaling/v1",
517 FieldsType: "FieldsV1",
518 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
519 Subresource: "scale",
520 },
521 },
522 expected: []metav1.ManagedFieldsEntry{
523 {
524 Manager: "scale",
525 Operation: metav1.ManagedFieldsOperationUpdate,
526 APIVersion: "apps/v1",
527 FieldsType: "FieldsV1",
528 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
529 Subresource: "scale",
530 },
531 },
532 },
533 {
534 desc: "apply without stealing",
535 parent: []metav1.ManagedFieldsEntry{
536 {
537 Manager: "test",
538 Operation: metav1.ManagedFieldsOperationApply,
539 APIVersion: "apps/v1",
540 FieldsType: "FieldsV1",
541 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
542 },
543 },
544 subresource: []metav1.ManagedFieldsEntry{
545 {
546 Manager: "test",
547 Operation: metav1.ManagedFieldsOperationApply,
548 APIVersion: "autoscaling/v1",
549 FieldsType: "FieldsV1",
550 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
551 },
552 {
553 Manager: "test",
554 Operation: metav1.ManagedFieldsOperationApply,
555 APIVersion: "autoscaling/v1",
556 FieldsType: "FieldsV1",
557 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
558 Subresource: "scale",
559 },
560 },
561 expected: []metav1.ManagedFieldsEntry{
562 {
563 Manager: "test",
564 Operation: metav1.ManagedFieldsOperationApply,
565 APIVersion: "apps/v1",
566 FieldsType: "FieldsV1",
567 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{},"f:selector":{}}}`)},
568 },
569 {
570 Manager: "test",
571 Operation: metav1.ManagedFieldsOperationApply,
572 APIVersion: "apps/v1",
573 FieldsType: "FieldsV1",
574 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
575 Subresource: "scale",
576 },
577 },
578 },
579 {
580 desc: "drops the entry if the api version is unknown",
581 parent: []metav1.ManagedFieldsEntry{
582 {
583 Manager: "test",
584 Operation: metav1.ManagedFieldsOperationApply,
585 APIVersion: "apps/v1",
586 FieldsType: "FieldsV1",
587 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
588 },
589 {
590 Manager: "another-manager",
591 Operation: metav1.ManagedFieldsOperationApply,
592 APIVersion: "apps/v10",
593 FieldsType: "FieldsV1",
594 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
595 },
596 },
597 subresource: []metav1.ManagedFieldsEntry{
598 {
599 Manager: "scale",
600 Operation: metav1.ManagedFieldsOperationUpdate,
601 APIVersion: "autoscaling/v1",
602 FieldsType: "FieldsV1",
603 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
604 },
605 },
606 expected: []metav1.ManagedFieldsEntry{
607 {
608 Manager: "scale",
609 Operation: metav1.ManagedFieldsOperationUpdate,
610 APIVersion: "apps/v1",
611 FieldsType: "FieldsV1",
612 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
613 },
614 },
615 },
616 }
617
618 for _, test := range tests {
619 t.Run(test.desc, func(t *testing.T) {
620 handler := NewScaleHandler(
621 test.parent,
622 schema.GroupVersion{Group: "apps", Version: "v1"},
623 defaultMappings(),
624 )
625 parentEntries, err := handler.ToParent(test.subresource)
626 if err != nil {
627 t.Fatalf("test: %q - expected no error but got %v", test.desc, err)
628 }
629 if !reflect.DeepEqual(parentEntries, test.expected) {
630 t.Fatalf("test: %q - expected output to be:\n%v\n\nbut got:\n%v", test.desc, test.expected, parentEntries)
631 }
632 })
633 }
634 }
635
636 func TestTransformingManagedFieldsToParentMultiVersion(t *testing.T) {
637 tests := []struct {
638 desc string
639 groupVersion schema.GroupVersion
640 mappings ResourcePathMappings
641 parent []metav1.ManagedFieldsEntry
642 subresource []metav1.ManagedFieldsEntry
643 expected []metav1.ManagedFieldsEntry
644 }{
645 {
646 desc: "multi-version",
647 groupVersion: schema.GroupVersion{Group: "apps", Version: "v1"},
648 mappings: ResourcePathMappings{
649 "apps/v1": fieldpath.MakePathOrDie("spec", "the-replicas"),
650 "apps/v2": fieldpath.MakePathOrDie("spec", "not-the-replicas"),
651 },
652 parent: []metav1.ManagedFieldsEntry{
653 {
654 Manager: "test",
655 Operation: metav1.ManagedFieldsOperationApply,
656 APIVersion: "apps/v1",
657 FieldsType: "FieldsV1",
658 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:the-replicas":{},"f:selector":{}}}`)},
659 },
660 {
661 Manager: "test-other",
662 Operation: metav1.ManagedFieldsOperationApply,
663 APIVersion: "apps/v2",
664 FieldsType: "FieldsV1",
665 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:not-the-replicas":{},"f:selector":{}}}`)},
666 },
667 },
668 subresource: []metav1.ManagedFieldsEntry{
669 {
670 Manager: "scale",
671 Operation: metav1.ManagedFieldsOperationUpdate,
672 APIVersion: "autoscaling/v1",
673 FieldsType: "FieldsV1",
674 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
675 Subresource: "scale",
676 },
677 },
678 expected: []metav1.ManagedFieldsEntry{
679 {
680 Manager: "test",
681 Operation: metav1.ManagedFieldsOperationApply,
682 APIVersion: "apps/v1",
683 FieldsType: "FieldsV1",
684 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
685 },
686 {
687 Manager: "test-other",
688 Operation: metav1.ManagedFieldsOperationApply,
689 APIVersion: "apps/v2",
690 FieldsType: "FieldsV1",
691 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
692 },
693 {
694 Manager: "scale",
695 Operation: metav1.ManagedFieldsOperationUpdate,
696 APIVersion: "apps/v1",
697 FieldsType: "FieldsV1",
698 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:the-replicas":{}}}`)},
699 Subresource: "scale",
700 },
701 },
702 },
703 {
704 desc: "Custom resource without scale subresource, scaling a version with `scale`",
705 groupVersion: schema.GroupVersion{Group: "mygroup", Version: "v1"},
706 mappings: ResourcePathMappings{
707 "mygroup/v1": fieldpath.MakePathOrDie("spec", "the-replicas"),
708 "mygroup/v2": nil,
709 },
710 parent: []metav1.ManagedFieldsEntry{
711 {
712 Manager: "test",
713 Operation: metav1.ManagedFieldsOperationApply,
714 APIVersion: "mygroup/v1",
715 FieldsType: "FieldsV1",
716 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:the-replicas":{},"f:selector":{}}}`)},
717 },
718 {
719 Manager: "test-other",
720 Operation: metav1.ManagedFieldsOperationApply,
721 APIVersion: "mygroup/v2",
722 FieldsType: "FieldsV1",
723 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:test-other":{}}}`)},
724 },
725 },
726 subresource: []metav1.ManagedFieldsEntry{
727 {
728 Manager: "scale",
729 Operation: metav1.ManagedFieldsOperationUpdate,
730 APIVersion: "autoscaling/v1",
731 FieldsType: "FieldsV1",
732 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:replicas":{}}}`)},
733 Subresource: "scale",
734 },
735 },
736 expected: []metav1.ManagedFieldsEntry{
737 {
738 Manager: "test",
739 Operation: metav1.ManagedFieldsOperationApply,
740 APIVersion: "mygroup/v1",
741 FieldsType: "FieldsV1",
742 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:selector":{}}}`)},
743 },
744 {
745 Manager: "test-other",
746 Operation: metav1.ManagedFieldsOperationApply,
747 APIVersion: "mygroup/v2",
748 FieldsType: "FieldsV1",
749 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:test-other":{}}}`)},
750 },
751 {
752 Manager: "scale",
753 Operation: metav1.ManagedFieldsOperationUpdate,
754 APIVersion: "mygroup/v1",
755 FieldsType: "FieldsV1",
756 FieldsV1: &metav1.FieldsV1{Raw: []byte(`{"f:spec":{"f:the-replicas":{}}}`)},
757 Subresource: "scale",
758 },
759 },
760 },
761 }
762
763 for _, test := range tests {
764 t.Run(test.desc, func(t *testing.T) {
765 handler := NewScaleHandler(
766 test.parent,
767 test.groupVersion,
768 test.mappings,
769 )
770 parentEntries, err := handler.ToParent(test.subresource)
771 if err != nil {
772 t.Fatalf("test: %q - expected no error but got %v", test.desc, err)
773 }
774 if !reflect.DeepEqual(parentEntries, test.expected) {
775 t.Fatalf("test: %q - expected output to be:\n%v\n\nbut got:\n%v", test.desc, test.expected, parentEntries)
776 }
777 })
778 }
779 }
780
781 func defaultMappings() ResourcePathMappings {
782 return ResourcePathMappings{
783 "apps/v1": fieldpath.MakePathOrDie("spec", "replicas"),
784 }
785 }
786
View as plain text