1
2
3
4 package runtimeutil
5
6 import (
7 "fmt"
8 "io"
9 "os"
10 "strings"
11 "testing"
12
13 "github.com/stretchr/testify/assert"
14 "sigs.k8s.io/kustomize/kyaml/yaml"
15 )
16
17 type testRun struct {
18 err error
19 expectedInput string
20 output string
21 t *testing.T
22 }
23
24 func (r testRun) run(reader io.Reader, writer io.Writer) error {
25 if r.expectedInput != "" {
26 input, err := io.ReadAll(reader)
27 if !assert.NoError(r.t, err) {
28 r.t.FailNow()
29 }
30
31
32 if !assert.Equal(r.t, r.expectedInput, string(input)) {
33 r.t.FailNow()
34 }
35 }
36
37 _, err := writer.Write([]byte(r.output))
38 if !assert.NoError(r.t, err) {
39 r.t.FailNow()
40 }
41
42 return r.err
43 }
44
45 func TestFunctionFilter_Filter(t *testing.T) {
46 var tests = []struct {
47 run testRun
48 name string
49 input []string
50 functionConfig string
51 expectedOutput []string
52 expectedError string
53 expectedSavedError string
54 expectedResults string
55 noMakeResultsFile bool
56 instance FunctionFilter
57 }{
58
59
60 {
61 name: "default file path annotation",
62 run: testRun{
63 output: `
64 apiVersion: config.kubernetes.io/v1
65 kind: ResourceList
66 items:
67 - apiVersion: apps/v1
68 kind: Deployment
69 metadata:
70 name: deployment-foo
71 - apiVersion: v1
72 kind: Service
73 metadata:
74 name: service-foo
75 `,
76 },
77 expectedOutput: []string{
78 `
79 apiVersion: apps/v1
80 kind: Deployment
81 metadata:
82 name: deployment-foo
83 annotations:
84 internal.config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
85 config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
86 `,
87 `
88 apiVersion: v1
89 kind: Service
90 metadata:
91 name: service-foo
92 annotations:
93 internal.config.kubernetes.io/path: 'service_service-foo.yaml'
94 config.kubernetes.io/path: 'service_service-foo.yaml'
95 `,
96 },
97 },
98
99
100
101 {
102 name: "no default file path annotation",
103 run: testRun{
104 output: `
105 apiVersion: config.kubernetes.io/v1
106 kind: ResourceList
107 items:
108 - apiVersion: apps/v1
109 kind: Deployment
110 metadata:
111 name: deployment-foo
112 - apiVersion: v1
113 kind: Service
114 metadata:
115 name: service-foo
116 annotations:
117 config.kubernetes.io/path: 'foo.yaml'
118 `,
119 },
120 expectedOutput: []string{
121 `
122 apiVersion: apps/v1
123 kind: Deployment
124 metadata:
125 name: deployment-foo
126 annotations:
127 internal.config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
128 config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
129 `,
130 `
131 apiVersion: v1
132 kind: Service
133 metadata:
134 name: service-foo
135 annotations:
136 config.kubernetes.io/path: 'foo.yaml'
137 internal.config.kubernetes.io/path: 'foo.yaml'
138 `,
139 },
140 },
141
142
143
144 {
145 name: "write read",
146 run: testRun{
147 output: `
148 apiVersion: config.kubernetes.io/v1
149 kind: ResourceList
150 items:
151 - apiVersion: v1
152 kind: Service
153 metadata:
154 name: service-foo
155 annotations:
156 config.kubernetes.io/path: 'foo.yaml'
157 - apiVersion: v1
158 kind: ConfigMap
159 metadata:
160 name: configmap-foo
161 annotations:
162 config.kubernetes.io/path: 'foo.yaml'
163 `,
164 },
165 input: []string{
166 `
167 apiVersion: apps/v1
168 kind: Deployment
169 metadata:
170 name: deployment-foo
171 `,
172 `
173 apiVersion: v1
174 kind: Service
175 metadata:
176 name: service-foo
177 `,
178 },
179 expectedOutput: []string{`
180 apiVersion: v1
181 kind: Service
182 metadata:
183 name: service-foo
184 annotations:
185 config.kubernetes.io/path: 'foo.yaml'
186 internal.config.kubernetes.io/path: 'foo.yaml'
187 `,
188 `
189 apiVersion: v1
190 kind: ConfigMap
191 metadata:
192 name: configmap-foo
193 annotations:
194 config.kubernetes.io/path: 'foo.yaml'
195 internal.config.kubernetes.io/path: 'foo.yaml'
196 `,
197 },
198 },
199
200
201
202 {
203 name: "write results file",
204 run: testRun{
205 output: `apiVersion: config.kubernetes.io/v1
206 kind: ResourceList
207 items:
208 - apiVersion: apps/v1
209 kind: Deployment
210 metadata:
211 name: deployment-foo
212 - apiVersion: v1
213 kind: Service
214 metadata:
215 name: service-foo
216 results:
217 - apiVersion: config.k8s.io/v1alpha1
218 kind: ObjectError
219 name: "some-validator"
220 items:
221 - type: error
222 message: "some message"
223 resourceRef:
224 apiVersion: apps/v1
225 kind: Deployment
226 name: foo
227 namespace: bar
228 file:
229 path: deploy.yaml
230 index: 0
231 field:
232 path: "spec.template.spec.containers[3].resources.limits.cpu"
233 currentValue: "200"
234 suggestedValue: "2"
235 `,
236 },
237 expectedOutput: []string{`
238 apiVersion: apps/v1
239 kind: Deployment
240 metadata:
241 name: deployment-foo
242 annotations:
243 internal.config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
244 config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
245 `, `
246 apiVersion: v1
247 kind: Service
248 metadata:
249 name: service-foo
250 annotations:
251 internal.config.kubernetes.io/path: 'service_service-foo.yaml'
252 config.kubernetes.io/path: 'service_service-foo.yaml'
253 `,
254 },
255 expectedResults: `
256 - apiVersion: config.k8s.io/v1alpha1
257 kind: ObjectError
258 name: "some-validator"
259 items:
260 - type: error
261 message: "some message"
262 resourceRef:
263 apiVersion: apps/v1
264 kind: Deployment
265 name: foo
266 namespace: bar
267 file:
268 path: deploy.yaml
269 index: 0
270 field:
271 path: "spec.template.spec.containers[3].resources.limits.cpu"
272 currentValue: "200"
273 suggestedValue: "2"
274 `,
275 },
276
277
278
279 {
280 name: "write results file function exit non 0",
281 expectedError: "failed",
282 run: testRun{
283 err: fmt.Errorf("failed"),
284 output: `
285 apiVersion: config.kubernetes.io/v1
286 kind: ResourceList
287 items:
288 - apiVersion: apps/v1
289 kind: Deployment
290 metadata:
291 name: deployment-foo
292 - apiVersion: v1
293 kind: Service
294 metadata:
295 name: service-foo
296 results:
297 - apiVersion: config.k8s.io/v1alpha1
298 kind: ObjectError
299 name: "some-validator"
300 items:
301 - type: error
302 message: "some message"
303 resourceRef:
304 apiVersion: apps/v1
305 kind: Deployment
306 name: foo
307 namespace: bar
308 file:
309 path: deploy.yaml
310 index: 0
311 field:
312 path: "spec.template.spec.containers[3].resources.limits.cpu"
313 currentValue: "200"
314 suggestedValue: "2"
315 `,
316 },
317 expectedOutput: []string{
318 `
319 apiVersion: apps/v1
320 kind: Deployment
321 metadata:
322 name: deployment-foo
323 annotations:
324 config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
325 `, `
326 apiVersion: v1
327 kind: Service
328 metadata:
329 name: service-foo
330 annotations:
331 config.kubernetes.io/path: 'service_service-foo.yaml'
332 `,
333 },
334 expectedResults: `
335 - apiVersion: config.k8s.io/v1alpha1
336 kind: ObjectError
337 name: "some-validator"
338 items:
339 - type: error
340 message: "some message"
341 resourceRef:
342 apiVersion: apps/v1
343 kind: Deployment
344 name: foo
345 namespace: bar
346 file:
347 path: deploy.yaml
348 index: 0
349 field:
350 path: "spec.template.spec.containers[3].resources.limits.cpu"
351 currentValue: "200"
352 suggestedValue: "2"
353 `,
354 },
355
356
357
358 {
359 name: "write results defer failure",
360 instance: FunctionFilter{DeferFailure: true},
361 expectedSavedError: "failed",
362 run: testRun{
363 err: fmt.Errorf("failed"),
364 output: `
365 apiVersion: config.kubernetes.io/v1
366 kind: ResourceList
367 items:
368 - apiVersion: apps/v1
369 kind: Deployment
370 metadata:
371 name: deployment-foo
372 - apiVersion: v1
373 kind: Service
374 metadata:
375 name: service-foo
376 results:
377 - apiVersion: config.k8s.io/v1alpha1
378 kind: ObjectError
379 name: "some-validator"
380 items:
381 - type: error
382 message: "some message"
383 resourceRef:
384 apiVersion: apps/v1
385 kind: Deployment
386 name: foo
387 namespace: bar
388 file:
389 path: deploy.yaml
390 index: 0
391 field:
392 path: "spec.template.spec.containers[3].resources.limits.cpu"
393 currentValue: "200"
394 suggestedValue: "2"`,
395 },
396 expectedOutput: []string{
397 `
398 apiVersion: apps/v1
399 kind: Deployment
400 metadata:
401 name: deployment-foo
402 annotations:
403 internal.config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
404 config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
405 `, `
406 apiVersion: v1
407 kind: Service
408 metadata:
409 name: service-foo
410 annotations:
411 internal.config.kubernetes.io/path: 'service_service-foo.yaml'
412 config.kubernetes.io/path: 'service_service-foo.yaml'
413 `,
414 },
415 expectedResults: `
416 - apiVersion: config.k8s.io/v1alpha1
417 kind: ObjectError
418 name: "some-validator"
419 items:
420 - type: error
421 message: "some message"
422 resourceRef:
423 apiVersion: apps/v1
424 kind: Deployment
425 name: foo
426 namespace: bar
427 file:
428 path: deploy.yaml
429 index: 0
430 field:
431 path: "spec.template.spec.containers[3].resources.limits.cpu"
432 currentValue: "200"
433 suggestedValue: "2"`,
434 },
435
436 {
437 name: "write results bad results file",
438 expectedError: "open /not/real/file:",
439 noMakeResultsFile: true,
440 run: testRun{
441 output: `
442 apiVersion: config.kubernetes.io/v1
443 kind: ResourceList
444 items:
445 - apiVersion: apps/v1
446 kind: Deployment
447 metadata:
448 name: deployment-foo
449 - apiVersion: v1
450 kind: Service
451 metadata:
452 name: service-foo
453 results:
454 - apiVersion: config.k8s.io/v1alpha1
455 name: "some-validator"
456 `,
457 },
458 expectedOutput: []string{
459 `
460 apiVersion: apps/v1
461 kind: Deployment
462 metadata:
463 name: deployment-foo
464 annotations:
465 config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
466 `, `
467 apiVersion: v1
468 kind: Service
469 metadata:
470 name: service-foo
471 annotations:
472 config.kubernetes.io/path: 'service_service-foo.yaml'
473 `,
474 },
475
476 expectedResults: `
477 - apiVersion: config.k8s.io/v1alpha1
478 name: "some-validator"
479 `,
480 },
481
482
483
484
485
486 {
487 name: "scope resources by directory",
488 run: testRun{
489 expectedInput: `apiVersion: config.kubernetes.io/v1
490 kind: ResourceList
491 items:
492 - apiVersion: v1
493 kind: Service
494 metadata:
495 name: service-foo
496 annotations:
497 config.kubernetes.io/path: 'foo/bar/s.yaml'
498 internal.config.kubernetes.io/id: '1'
499 config.k8s.io/id: '1'
500 functionConfig:
501 apiVersion: example.com/v1
502 kind: Example
503 metadata:
504 name: foo
505 annotations:
506 config.kubernetes.io/path: 'foo/bar.yaml'
507 `,
508 output: `apiVersion: config.kubernetes.io/v1
509 kind: ResourceList
510 items:
511 - apiVersion: v1
512 kind: Service
513 metadata:
514 name: service-foo
515 annotations:
516 config.kubernetes.io/path: 'foo/bar/s.yaml'
517 new: annotation
518 internal.config.kubernetes.io/id: '1'
519 functionConfig:
520 apiVersion: example.com/v1
521 kind: Example
522 metadata:
523 name: foo
524 annotations:
525 config.kubernetes.io/path: 'foo/bar.yaml'
526 `,
527 },
528 functionConfig: `
529 apiVersion: example.com/v1
530 kind: Example
531 metadata:
532 name: foo
533 annotations:
534 config.kubernetes.io/path: 'foo/bar.yaml'
535 `,
536 input: []string{
537
538 `
539 apiVersion: apps/v1
540 kind: Deployment
541 metadata:
542 name: deployment-foo
543 annotations:
544 config.kubernetes.io/path: 'baz/bar/d.yaml'
545 `,
546
547 `
548 apiVersion: v1
549 kind: Service
550 metadata:
551 name: service-foo
552 annotations:
553 config.kubernetes.io/path: 'foo/bar/s.yaml'
554 `},
555 expectedOutput: []string{
556 `
557 apiVersion: v1
558 kind: Service
559 metadata:
560 name: service-foo
561 annotations:
562 config.kubernetes.io/path: 'foo/bar/s.yaml'
563 new: annotation
564 internal.config.kubernetes.io/path: 'foo/bar/s.yaml'
565 `, `
566 apiVersion: apps/v1
567 kind: Deployment
568 metadata:
569 name: deployment-foo
570 annotations:
571 config.kubernetes.io/path: 'baz/bar/d.yaml'
572 `,
573 },
574 },
575
576
577 {
578 name: "scope resources by directory resources missing path",
579 run: testRun{
580 expectedInput: `apiVersion: config.kubernetes.io/v1
581 kind: ResourceList
582 items:
583 - apiVersion: v1
584 kind: Service
585 metadata:
586 name: service-foo
587 annotations:
588 config.kubernetes.io/path: 'foo/bar/s.yaml'
589 internal.config.kubernetes.io/id: '1'
590 config.k8s.io/id: '1'
591 functionConfig:
592 apiVersion: example.com/v1
593 kind: Example
594 metadata:
595 name: foo
596 annotations:
597 config.kubernetes.io/path: 'foo/bar.yaml'
598 `,
599 output: `apiVersion: config.kubernetes.io/v1
600 kind: ResourceList
601 items:
602 - apiVersion: v1
603 kind: Service
604 metadata:
605 name: service-foo
606 annotations:
607 config.kubernetes.io/path: 'foo/bar/s.yaml'
608 new: annotation
609 internal.config.kubernetes.io/id: '1'
610 functionConfig:
611 apiVersion: example.com/v1
612 kind: Example
613 metadata:
614 name: foo
615 annotations:
616 config.kubernetes.io/path: 'foo/bar.yaml'
617 `,
618 },
619 functionConfig: `
620 apiVersion: example.com/v1
621 kind: Example
622 metadata:
623 name: foo
624 annotations:
625 config.kubernetes.io/path: 'foo/bar.yaml'
626 `,
627 input: []string{
628
629 `
630 apiVersion: apps/v1
631 kind: Deployment
632 metadata:
633 name: deployment-foo
634 `,
635
636 `
637 apiVersion: v1
638 kind: Service
639 metadata:
640 name: service-foo
641 annotations:
642 config.kubernetes.io/path: 'foo/bar/s.yaml'
643 `},
644 expectedOutput: []string{
645 `
646 apiVersion: v1
647 kind: Service
648 metadata:
649 name: service-foo
650 annotations:
651 config.kubernetes.io/path: 'foo/bar/s.yaml'
652 new: annotation
653 internal.config.kubernetes.io/path: 'foo/bar/s.yaml'
654 `, `
655 apiVersion: apps/v1
656 kind: Deployment
657 metadata:
658 name: deployment-foo
659 `,
660 },
661 },
662
663
664 {
665 name: "scope resources global",
666 instance: FunctionFilter{GlobalScope: true},
667 run: testRun{
668 expectedInput: `apiVersion: config.kubernetes.io/v1
669 kind: ResourceList
670 items:
671 - apiVersion: apps/v1
672 kind: Deployment
673 metadata:
674 name: deployment-foo
675 annotations:
676 config.kubernetes.io/path: 'baz/bar/d.yaml'
677 internal.config.kubernetes.io/id: '1'
678 config.k8s.io/id: '1'
679 - apiVersion: v1
680 kind: Service
681 metadata:
682 name: service-foo
683 annotations:
684 config.kubernetes.io/path: 'foo/bar/s.yaml'
685 internal.config.kubernetes.io/id: '2'
686 config.k8s.io/id: '2'
687 functionConfig:
688 apiVersion: example.com/v1
689 kind: Example
690 metadata:
691 name: foo
692 annotations:
693 config.kubernetes.io/path: 'foo/bar.yaml'
694 `,
695 output: `apiVersion: config.kubernetes.io/v1
696 kind: ResourceList
697 items:
698 - apiVersion: apps/v1
699 kind: Deployment
700 metadata:
701 name: deployment-foo
702 annotations:
703 config.kubernetes.io/path: 'baz/bar/d.yaml'
704 internal.config.kubernetes.io/id: '1'
705 - apiVersion: v1
706 kind: Service
707 metadata:
708 name: service-foo
709 annotations:
710 config.kubernetes.io/path: 'foo/bar/s.yaml'
711 new: annotation
712 config.k8s.io/id: '2'
713 functionConfig:
714 apiVersion: example.com/v1
715 kind: Example
716 metadata:
717 name: foo
718 annotations:
719 config.kubernetes.io/path: 'foo/bar.yaml'
720 `,
721 },
722 functionConfig: `
723 apiVersion: example.com/v1
724 kind: Example
725 metadata:
726 name: foo
727 annotations:
728 config.kubernetes.io/path: 'foo/bar.yaml'
729 `,
730 input: []string{
731 `
732 apiVersion: apps/v1
733 kind: Deployment
734 metadata:
735 name: deployment-foo
736 annotations:
737 config.kubernetes.io/path: 'baz/bar/d.yaml'
738 `,
739 `
740 apiVersion: v1
741 kind: Service
742 metadata:
743 name: service-foo
744 annotations:
745 config.kubernetes.io/path: 'foo/bar/s.yaml'
746 `},
747 expectedOutput: []string{
748 `
749 apiVersion: apps/v1
750 kind: Deployment
751 metadata:
752 name: deployment-foo
753 annotations:
754 config.kubernetes.io/path: 'baz/bar/d.yaml'
755 internal.config.kubernetes.io/path: 'baz/bar/d.yaml'
756 `, `
757 apiVersion: v1
758 kind: Service
759 metadata:
760 name: service-foo
761 annotations:
762 config.kubernetes.io/path: 'foo/bar/s.yaml'
763 new: annotation
764 internal.config.kubernetes.io/path: 'foo/bar/s.yaml'
765 `,
766 },
767 },
768
769 {
770 name: "scope no resources",
771 run: testRun{
772 expectedInput: `apiVersion: config.kubernetes.io/v1
773 kind: ResourceList
774 items: []
775 functionConfig:
776 apiVersion: example.com/v1
777 kind: Example
778 metadata:
779 name: foo
780 annotations:
781 config.kubernetes.io/path: 'foo/bar.yaml'
782 `,
783 output: `apiVersion: config.kubernetes.io/v1
784 kind: ResourceList
785 items: []
786 functionConfig:
787 apiVersion: example.com/v1
788 kind: Example
789 metadata:
790 name: foo
791 annotations:
792 config.kubernetes.io/path: 'foo/bar.yaml'
793 `,
794 },
795 functionConfig: `
796 apiVersion: example.com/v1
797 kind: Example
798 metadata:
799 name: foo
800 annotations:
801 config.kubernetes.io/path: 'foo/bar.yaml'
802 `,
803 input: []string{
804
805 `
806 apiVersion: apps/v1
807 kind: Deployment
808 metadata:
809 name: deployment-foo
810 annotations:
811 config.kubernetes.io/path: 'baz/bar/d.yaml'
812 `, `
813 apiVersion: v1
814 kind: Service
815 metadata:
816 name: service-foo
817 annotations:
818 config.kubernetes.io/path: 'biz/bar/s.yaml'
819 `},
820 expectedOutput: []string{
821 `
822 apiVersion: apps/v1
823 kind: Deployment
824 metadata:
825 name: deployment-foo
826 annotations:
827 config.kubernetes.io/path: 'baz/bar/d.yaml'
828 `, `
829 apiVersion: v1
830 kind: Service
831 metadata:
832 name: service-foo
833 annotations:
834 config.kubernetes.io/path: 'biz/bar/s.yaml'
835 `,
836 },
837 },
838
839 {
840 name: "scope functions dir",
841 run: testRun{
842 expectedInput: `apiVersion: config.kubernetes.io/v1
843 kind: ResourceList
844 items:
845 - apiVersion: v1
846 kind: Service
847 metadata:
848 name: service-foo
849 annotations:
850 config.kubernetes.io/path: 'foo/bar/s.yaml'
851 internal.config.kubernetes.io/id: '1'
852 config.k8s.io/id: '1'
853 functionConfig:
854 apiVersion: example.com/v1
855 kind: Example
856 metadata:
857 name: foo
858 annotations:
859 config.kubernetes.io/path: 'foo/functions/bar.yaml'
860 `,
861 output: `apiVersion: config.kubernetes.io/v1
862 kind: ResourceList
863 items:
864 - apiVersion: v1
865 kind: Service
866 metadata:
867 name: service-foo
868 annotations:
869 config.kubernetes.io/path: 'foo/bar/s.yaml'
870 internal.config.kubernetes.io/id: '1'
871 new: annotation
872 internal.config.kubernetes.io/path: 'foo/bar/s.yaml'
873 functionConfig:
874 apiVersion: example.com/v1
875 kind: Example
876 metadata:
877 name: foo
878 annotations:
879 config.kubernetes.io/path: 'foo/functions/bar.yaml'
880 `,
881 },
882 functionConfig: `
883 apiVersion: example.com/v1
884 kind: Example
885 metadata:
886 name: foo
887 annotations:
888 config.kubernetes.io/path: 'foo/functions/bar.yaml'
889 `,
890 input: []string{
891
892 `
893 apiVersion: apps/v1
894 kind: Deployment
895 metadata:
896 name: deployment-foo
897 annotations:
898 config.kubernetes.io/path: 'baz/bar/d.yaml'
899 `,
900
901 `
902 apiVersion: v1
903 kind: Service
904 metadata:
905 name: service-foo
906 annotations:
907 config.kubernetes.io/path: 'foo/bar/s.yaml'
908 `},
909 expectedOutput: []string{
910 `
911 apiVersion: v1
912 kind: Service
913 metadata:
914 name: service-foo
915 annotations:
916 config.kubernetes.io/path: 'foo/bar/s.yaml'
917 new: annotation
918 internal.config.kubernetes.io/path: 'foo/bar/s.yaml'
919 `, `
920 apiVersion: apps/v1
921 kind: Deployment
922 metadata:
923 name: deployment-foo
924 annotations:
925 config.kubernetes.io/path: 'baz/bar/d.yaml'
926 `,
927 },
928 },
929
930 {
931 name: "copy comments",
932 run: testRun{
933 expectedInput: `apiVersion: config.kubernetes.io/v1
934 kind: ResourceList
935 items:
936 - apiVersion: apps/v1
937 kind: Deployment
938 metadata:
939 name: deployment-foo
940 annotations:
941 config.kubernetes.io/path: 'foo/b.yaml'
942 internal.config.kubernetes.io/id: '1'
943 config.k8s.io/id: '1'
944 - apiVersion: v1
945 kind: Service
946 metadata:
947 name: service-foo # name comment
948 annotations:
949 config.kubernetes.io/path: 'foo/a.yaml'
950 internal.config.kubernetes.io/id: '2'
951 config.k8s.io/id: '2'
952 functionConfig:
953 apiVersion: example.com/v1
954 kind: Example
955 metadata:
956 name: foo
957 annotations:
958 config.kubernetes.io/path: 'foo/f.yaml'
959 `,
960
961 output: `apiVersion: config.kubernetes.io/v1
962 kind: ResourceList
963 items:
964 - apiVersion: apps/v1
965 kind: Deployment
966 metadata:
967 name: deployment-foo
968 annotations:
969 config.kubernetes.io/path: 'foo/b.yaml'
970 internal.config.kubernetes.io/id: '1'
971 - apiVersion: v1
972 kind: Service
973 metadata:
974 name: service-foo
975 annotations:
976 config.kubernetes.io/path: 'foo/a.yaml'
977 internal.config.kubernetes.io/id: '2'
978 new: annotation
979 functionConfig:
980 apiVersion: example.com/v1
981 kind: Example
982 metadata:
983 name: foo
984 annotations:
985 config.kubernetes.io/path: 'foo/f.yaml'
986 `,
987 },
988 functionConfig: `
989 apiVersion: example.com/v1
990 kind: Example
991 metadata:
992 name: foo
993 annotations:
994 config.kubernetes.io/path: 'foo/f.yaml'
995 `,
996 input: []string{
997 `
998 apiVersion: apps/v1
999 kind: Deployment
1000 metadata:
1001 name: deployment-foo
1002 annotations:
1003 config.kubernetes.io/path: 'foo/b.yaml'
1004 `,
1005 `
1006 apiVersion: v1
1007 kind: Service
1008 metadata:
1009 name: service-foo # name comment
1010 annotations:
1011 config.kubernetes.io/path: 'foo/a.yaml'
1012 `},
1013 expectedOutput: []string{
1014 `
1015 apiVersion: apps/v1
1016 kind: Deployment
1017 metadata:
1018 name: deployment-foo
1019 annotations:
1020 config.kubernetes.io/path: 'foo/b.yaml'
1021 internal.config.kubernetes.io/path: 'foo/b.yaml'
1022 `, `
1023 apiVersion: v1
1024 kind: Service
1025 metadata:
1026 name: service-foo # name comment
1027 annotations:
1028 config.kubernetes.io/path: 'foo/a.yaml'
1029 new: annotation
1030 internal.config.kubernetes.io/path: 'foo/a.yaml'
1031 `,
1032 },
1033 },
1034 }
1035
1036 for i := range tests {
1037 tt := tests[i]
1038 t.Run(tt.name, func(t *testing.T) {
1039
1040 if len(tt.expectedResults) > 0 && !tt.noMakeResultsFile {
1041
1042 f, err := os.CreateTemp("", "test-kyaml-*.yaml")
1043 if !assert.NoError(t, err) {
1044 t.FailNow()
1045 }
1046 defer os.RemoveAll(f.Name())
1047 tt.instance.ResultsFile = f.Name()
1048 } else if len(tt.expectedResults) > 0 {
1049
1050 tt.instance.ResultsFile = "/not/real/file"
1051 }
1052
1053
1054 var inputs []*yaml.RNode
1055 for i := range tt.input {
1056 node, err := yaml.Parse(tt.input[i])
1057 if !assert.NoError(t, err) {
1058 t.FailNow()
1059 }
1060 inputs = append(inputs, node)
1061 }
1062
1063
1064 tt.run.t = t
1065 tt.instance.Run = tt.run.run
1066 if tt.functionConfig != "" {
1067 fc, err := yaml.Parse(tt.functionConfig)
1068 if !assert.NoError(t, err) {
1069 t.FailNow()
1070 }
1071 tt.instance.FunctionConfig = fc
1072 }
1073 output, err := tt.instance.Filter(inputs)
1074 if tt.expectedError != "" {
1075 if !assert.Error(t, err) {
1076 t.FailNow()
1077 }
1078 if !assert.Contains(t, err.Error(), tt.expectedError) {
1079 t.FailNow()
1080 }
1081 return
1082 }
1083
1084
1085 if tt.expectedSavedError != "" {
1086 if !assert.EqualError(t, tt.instance.exit, tt.expectedSavedError) {
1087 t.FailNow()
1088 }
1089 }
1090
1091 if !assert.NoError(t, err) {
1092 t.FailNow()
1093 }
1094
1095
1096 var actual []string
1097 for i := range output {
1098 s, err := output[i].String()
1099 if !assert.NoError(t, err) {
1100 t.FailNow()
1101 }
1102 actual = append(actual, strings.TrimSpace(s))
1103 }
1104 var expected []string
1105 for i := range tt.expectedOutput {
1106 expected = append(expected, strings.TrimSpace(tt.expectedOutput[i]))
1107 }
1108
1109 if !assert.Equal(t, expected, actual) {
1110 t.FailNow()
1111 }
1112
1113
1114 if len(tt.instance.ResultsFile) > 0 {
1115 tt.expectedResults = strings.TrimSpace(tt.expectedResults)
1116
1117 results, err := tt.instance.Results.String()
1118 if !assert.NoError(t, err) {
1119 t.FailNow()
1120 }
1121 if !assert.Equal(t, tt.expectedResults, strings.TrimSpace(results)) {
1122 t.FailNow()
1123 }
1124
1125 b, err := os.ReadFile(tt.instance.ResultsFile)
1126 writtenResults := strings.TrimSpace(string(b))
1127 if !assert.NoError(t, err) {
1128 t.FailNow()
1129 }
1130 if !assert.Equal(t, tt.expectedResults, writtenResults) {
1131 t.FailNow()
1132 }
1133 }
1134 })
1135 }
1136 }
1137
1138 func Test_GetFunction(t *testing.T) {
1139 var tests = []struct {
1140 name string
1141 resource string
1142 expectedFn string
1143 missingFn bool
1144 }{
1145
1146
1147 {
1148 name: "fn annotation",
1149 resource: `
1150 apiVersion: v1beta1
1151 kind: Example
1152 metadata:
1153 annotations:
1154 config.kubernetes.io/function: |-
1155 container:
1156 image: foo:v1.0.0
1157 `,
1158 expectedFn: `
1159 container:
1160 image: foo:v1.0.0`,
1161 },
1162
1163 {
1164 name: "storage mounts json style",
1165 resource: `
1166 apiVersion: v1beta1
1167 kind: Example
1168 metadata:
1169 annotations:
1170 config.kubernetes.io/function: |-
1171 container:
1172 image: foo:v1.0.0
1173 mounts: [ {type: bind, src: /mount/path, dst: /local/}, {src: myvol, dst: /local/, type: volume}, {dst: /local/, type: tmpfs} ]
1174 `,
1175 expectedFn: `
1176 container:
1177 image: foo:v1.0.0
1178 mounts:
1179 - type: bind
1180 src: /mount/path
1181 dst: /local/
1182 - type: volume
1183 src: myvol
1184 dst: /local/
1185 - type: tmpfs
1186 dst: /local/
1187 `,
1188 },
1189
1190 {
1191 name: "storage mounts yaml style",
1192 resource: `
1193 apiVersion: v1beta1
1194 kind: Example
1195 metadata:
1196 annotations:
1197 config.kubernetes.io/function: |-
1198 container:
1199 image: foo:v1.0.0
1200 mounts:
1201 - src: /mount/path
1202 type: bind
1203 dst: /local/
1204 - dst: /local/
1205 src: myvol
1206 type: volume
1207 - type: tmpfs
1208 dst: /local/
1209 `,
1210 expectedFn: `
1211 container:
1212 image: foo:v1.0.0
1213 mounts:
1214 - type: bind
1215 src: /mount/path
1216 dst: /local/
1217 - type: volume
1218 src: myvol
1219 dst: /local/
1220 - type: tmpfs
1221 dst: /local/
1222 `,
1223 },
1224
1225 {
1226 name: "network",
1227 resource: `
1228 apiVersion: v1beta1
1229 kind: Example
1230 metadata:
1231 annotations:
1232 config.kubernetes.io/function: |-
1233 container:
1234 image: foo:v1.0.0
1235 network: true
1236 `,
1237 expectedFn: `
1238 container:
1239 image: foo:v1.0.0
1240 network: true
1241 `,
1242 },
1243
1244 {
1245 name: "path with uncorrect position",
1246 resource: `
1247 apiVersion: v1beta1
1248 kind: Example
1249 metadata:
1250 annotations:
1251 config.kubernetes.io/function: |-
1252 path: foo
1253 container:
1254 image: foo:v1.0.0
1255 `,
1256 missingFn: true,
1257 },
1258
1259 {
1260 name: "network with uncorrect position",
1261 resource: `
1262 apiVersion: v1beta1
1263 kind: Example
1264 metadata:
1265 annotations:
1266 config.kubernetes.io/function: |-
1267 network: foo
1268 container:
1269 image: foo:v1.0.0
1270 `,
1271 missingFn: true,
1272 },
1273 {
1274 name: "typo in function config",
1275 resource: `
1276 apiVersion: v1beta1
1277 kind: Example
1278 metadata:
1279 annotations:
1280 config.kubernetes.io/function: |-
1281 containeer:
1282 image: foo:v1.0.0
1283 `,
1284 missingFn: true,
1285 },
1286
1287
1288 {
1289 name: "legacy fn meta",
1290 resource: `
1291 apiVersion: v1beta1
1292 kind: Example
1293 metadata:
1294 configFn:
1295 container:
1296 image: foo:v1.0.0
1297 `,
1298 expectedFn: `
1299 container:
1300 image: foo:v1.0.0
1301 `,
1302 },
1303
1304
1305 {
1306 name: "no fn",
1307 resource: `
1308 apiVersion: v1beta1
1309 kind: Example
1310 metadata:
1311 annotations: {}
1312 `,
1313 missingFn: true,
1314 },
1315
1316
1317 }
1318
1319 for i := range tests {
1320 tt := tests[i]
1321 t.Run(tt.name, func(t *testing.T) {
1322 resource := yaml.MustParse(tt.resource)
1323 fn, err := GetFunctionSpec(resource)
1324 if tt.missingFn {
1325 if err == nil && !assert.Nil(t, fn) {
1326 t.FailNow()
1327 }
1328 return
1329 }
1330 b, err := yaml.Marshal(fn)
1331 if !assert.NoError(t, err) {
1332 t.FailNow()
1333 }
1334 if !assert.Equal(t,
1335 strings.TrimSpace(tt.expectedFn),
1336 strings.TrimSpace(string(b))) {
1337 t.FailNow()
1338 }
1339 })
1340 }
1341 }
1342
1343 func Test_GetContainerNetworkRequired(t *testing.T) {
1344 tests := []struct {
1345 input string
1346 required bool
1347 }{
1348 {
1349 input: `apiVersion: v1
1350 kind: Foo
1351 metadata:
1352 name: foo
1353 configFn:
1354 container:
1355 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
1356 network: true
1357 `,
1358 required: true,
1359 },
1360 {
1361 input: `apiVersion: v1
1362 kind: Foo
1363 metadata:
1364 name: foo
1365 configFn:
1366 container:
1367 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
1368 network: false
1369 `,
1370 required: false,
1371 },
1372 {
1373
1374 input: `apiVersion: v1
1375 kind: Foo
1376 metadata:
1377 name: foo
1378 configFn:
1379 container:
1380 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
1381 `,
1382 required: false,
1383 },
1384 {
1385 input: `apiVersion: v1
1386 kind: Foo
1387 metadata:
1388 name: foo
1389 annotations:
1390 config.kubernetes.io/function: |
1391 container:
1392 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
1393 network: true
1394 `,
1395 required: true,
1396 },
1397 }
1398
1399 for _, tc := range tests {
1400 cfg, err := yaml.Parse(tc.input)
1401 if !assert.NoError(t, err) {
1402 t.FailNow()
1403 }
1404 fn, err := GetFunctionSpec(cfg)
1405 if !assert.NoError(t, err) {
1406 t.FailNow()
1407 }
1408 assert.Equal(t, tc.required, fn.Container.Network)
1409 }
1410 }
1411
1412 func Test_StringToStorageMount(t *testing.T) {
1413 tests := []struct {
1414 in string
1415 expectedOut string
1416 }{
1417 {
1418 in: "type=bind,src=/tmp/test/,dst=/tmp/source/",
1419 expectedOut: "type=bind,source=/tmp/test/,target=/tmp/source/,readonly",
1420 },
1421 {
1422 in: "type=bind,src=/tmp/test/,dst=/tmp/source/,rw=true",
1423 expectedOut: "type=bind,source=/tmp/test/,target=/tmp/source/",
1424 },
1425 {
1426 in: "type=bind,src=/tmp/test/,dst=/tmp/source/,rw=false",
1427 expectedOut: "type=bind,source=/tmp/test/,target=/tmp/source/,readonly",
1428 },
1429 {
1430 in: "type=bind,src=/tmp/test/,dst=/tmp/source/,rw=",
1431 expectedOut: "type=bind,source=/tmp/test/,target=/tmp/source/,readonly",
1432 },
1433 {
1434 in: "type=tmpfs,src=/tmp/test/,dst=/tmp/source/,rw=invalid",
1435 expectedOut: "type=tmpfs,source=/tmp/test/,target=/tmp/source/,readonly",
1436 },
1437 {
1438 in: "type=tmpfs,src=/tmp/test/,dst=/tmp/source/,rwe=invalid",
1439 expectedOut: "type=tmpfs,source=/tmp/test/,target=/tmp/source/,readonly",
1440 },
1441 {
1442 in: "type=tmpfs,src=/tmp/test/,dst",
1443 expectedOut: "type=tmpfs,source=/tmp/test/,target=,readonly",
1444 },
1445 {
1446 in: "type=bind,source=/tmp/test/,target=/tmp/source/,rw=true",
1447 expectedOut: "type=bind,source=/tmp/test/,target=/tmp/source/",
1448 },
1449 {
1450 in: "type=bind,source=/tmp/test/,target=/tmp/source/",
1451 expectedOut: "type=bind,source=/tmp/test/,target=/tmp/source/,readonly",
1452 },
1453 }
1454
1455 for _, tc := range tests {
1456 s := StringToStorageMount(tc.in)
1457 assert.Equal(t, tc.expectedOut, (&s).String())
1458 }
1459 }
1460
1461 func TestContainerEnvGetDockerFlags(t *testing.T) {
1462 tests := []struct {
1463 input *ContainerEnv
1464 output []string
1465 }{
1466 {
1467 input: NewContainerEnvFromStringSlice([]string{"foo=bar"}),
1468 output: []string{"-e", "LOG_TO_STDERR=true", "-e", "STRUCTURED_RESULTS=true", "-e", "foo=bar"},
1469 },
1470 {
1471 input: NewContainerEnvFromStringSlice([]string{"foo"}),
1472 output: []string{"-e", "LOG_TO_STDERR=true", "-e", "STRUCTURED_RESULTS=true", "-e", "foo"},
1473 },
1474 {
1475 input: NewContainerEnvFromStringSlice([]string{"foo=bar", "baz"}),
1476 output: []string{"-e", "LOG_TO_STDERR=true", "-e", "STRUCTURED_RESULTS=true", "-e", "foo=bar", "-e", "baz"},
1477 },
1478 {
1479 input: NewContainerEnv(),
1480 output: []string{"-e", "LOG_TO_STDERR=true", "-e", "STRUCTURED_RESULTS=true"},
1481 },
1482 }
1483
1484 for _, tc := range tests {
1485 flags := tc.input.GetDockerFlags()
1486 assert.Equal(t, tc.output, flags)
1487 }
1488 }
1489
1490 func TestGetContainerEnv(t *testing.T) {
1491 tests := []struct {
1492 input string
1493 expected ContainerEnv
1494 }{
1495 {
1496 input: `
1497 apiVersion: v1
1498 kind: Foo
1499 metadata:
1500 name: foo
1501 configFn:
1502 container:
1503 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
1504 envs:
1505 - foo=bar
1506 `,
1507 expected: *NewContainerEnvFromStringSlice([]string{"foo=bar"}),
1508 },
1509 {
1510 input: `
1511 apiVersion: v1
1512 kind: Foo
1513 metadata:
1514 name: foo
1515 configFn:
1516 container:
1517 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
1518 envs:
1519 - foo=bar
1520 - baz
1521 `,
1522 expected: *NewContainerEnvFromStringSlice([]string{"foo=bar", "baz"}),
1523 },
1524 {
1525 input: `
1526 apiVersion: v1
1527 kind: Foo
1528 metadata:
1529 name: foo
1530 configFn:
1531 container:
1532 image: gcr.io/kustomize-functions/example-tshirt:v0.1.0
1533 envs:
1534 - KUBECONFIG
1535 `,
1536 expected: *NewContainerEnvFromStringSlice([]string{"KUBECONFIG"}),
1537 },
1538 }
1539
1540 for _, tc := range tests {
1541 cfg, err := yaml.Parse(tc.input)
1542 if !assert.NoError(t, err) {
1543 t.FailNow()
1544 }
1545 fn, err := GetFunctionSpec(cfg)
1546 if !assert.NoError(t, err) {
1547 t.FailNow()
1548 }
1549 assert.Equal(t, tc.expected, *NewContainerEnvFromStringSlice(fn.Container.Env))
1550 }
1551 }
1552
View as plain text