kubelatte-ce
Форк от sbertech/kubelatte-ce
822 строки · 20.7 Кб
1package mutation
2
3import (
4"context"
5"gitverse.ru/synapse/kubelatte/pkg/api/v1alpha1"
6"gitverse.ru/synapse/kubelatte/pkg/observability/logger/lib"
7"gitverse.ru/synapse/kubelatte/pkg/util"
8baseMatch "gitverse.ru/synapse/kubelatte/pkg/util/match"
9"go.uber.org/zap"
10"reflect"
11"testing"
12)
13
14var templateWithAContainer = v1alpha1.Template{
15Spec: v1alpha1.TemplateSpec{Data: `spec:
16containers:
17- name: container_mutated
18image: imagemut
19env:
20- name: env_name_mutated
21value: '_mutated'
22- name: ENV_10_mutated
23value: '_mutated'
24resources:
25limits:
26cpu: '55_mutated'
27memory: '55_mutated'
28requests:
29cpu: 55_mutated
30memory: 55_mutated
31args:
32- arg1mut
33securityContext:
34capabilities:
35drop:
36- ALL_mutated`,
37},
38}
39
40var templateWithContainers = v1alpha1.Template{
41Spec: v1alpha1.TemplateSpec{
42Data: `spec:
43containers:
44- name: container_mutated
45image: image-1
46env:
47- name: ENV_1_ADD
48value: 'false'
49- name: ENV_2
50value: 'false'
51- name: some-other-container
52image: image-2
53resources:
54limits:
55cpu: '51m'
56memory: '51Mi'
57requests:
58cpu: 50m
59memory: 50Mi`,
60},
61}
62
63var templateWithContainersWithIntersections = v1alpha1.Template{
64Spec: v1alpha1.TemplateSpec{
65Data: `spec:
66containers:
67- name: container_mutated
68image: image-1
69env:
70- name: ENV_1_ADD
71value: 'false'
72- name: ENV_2
73value: 'false'
74- name: some-other-container
75image: image-2
76resources:
77limits:
78cpu: '51m'
79memory: '51Mi'
80requests:
81cpu: 50m
82memory: 50Mi
83- name: container_mutated
84image: image-1-REPLACED
85env:
86- name: ENV_1_ADD-REPLACED
87value: 'false-REPLACED'
88- name: ENV_2-REPLACED
89value: 'false-REPLACED'
90`,
91},
92}
93
94var templateWithAVolume = v1alpha1.Template{
95Spec: v1alpha1.TemplateSpec{
96Data: `spec:
97volumes:
98- name: volume_mutated1
99configMap:
100name: istio`,
101},
102}
103
104var templateWithAVolumeWithIntersection = v1alpha1.Template{
105Spec: v1alpha1.TemplateSpec{
106Data: `spec:
107volumes:
108- name: volume_mutated1
109configMap:
110name: istio
111- name: volume_mutated1
112configMap:
113name: istio-REPLACED`,
114},
115}
116
117var templateWithVolumes = v1alpha1.Template{
118Spec: v1alpha1.TemplateSpec{
119Data: `spec:
120volumes:
121- name: volume_mutated1
122configMap:
123name: istio
124- name: volume_mutated2
125hostPath:
126path: /data
127type: Directory
128- name: volume_mutated3
129secret:
130secretName: mysecret
131optional: true`,
132},
133}
134
135var templateWithVolumesWithIntersections = v1alpha1.Template{
136Spec: v1alpha1.TemplateSpec{
137Data: `spec:
138volumes:
139- name: volume_mutated1
140configMap:
141name: istio
142- name: volume_mutated2
143hostPath:
144path: /data
145type: Directory
146- name: volume_mutated1
147configMap:
148name: istio-REPLACED
149secret:
150secretName: mysecret
151optional: true`,
152},
153}
154
155var templateWithAnAnnotation = v1alpha1.Template{
156Spec: v1alpha1.TemplateSpec{
157Data: `metadata:
158annotations:
159annotation_mutated1: val-after-mutation`,
160},
161}
162
163var templateWithAnnotations = v1alpha1.Template{
164Spec: v1alpha1.TemplateSpec{
165Data: `metadata:
166annotations:
167annotation_mutated1: val-after-mutation
168annotation_mutated2: another-val-after-mutation`,
169},
170}
171
172func TestMutateController_getRendersOldLogic(t *testing.T) {
173type args struct {
174obj map[string]interface{}
175config v1alpha1.MutationConfig
176}
177tests := []struct {
178name string
179args args
180
181templates map[string]v1alpha1.Template
182
183want []util.RenderItem
184}{
185{
186name: "merge_mutation_with_a_container",
187args: args{
188config: v1alpha1.MutationConfig{
189Name: "mutation cfg",
190UpdateStrategy: string(MergeStrategy),
191Containers: []string{"some-ns/some-templ/container_mutated"},
192},
193},
194templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAContainer},
195want: []util.RenderItem{{Render: `spec:
196containers:
197- args:
198- arg1mut
199env:
200- name: env_name_mutated
201value: _mutated
202- name: ENV_10_mutated
203value: _mutated
204image: imagemut
205name: container_mutated
206resources:
207limits:
208cpu: 55_mutated
209memory: 55_mutated
210requests:
211cpu: 55_mutated
212memory: 55_mutated
213securityContext:
214capabilities:
215drop:
216- ALL_mutated
217`}},
218},
219{
220name: "merge_mutation_with_containers",
221args: args{
222config: v1alpha1.MutationConfig{
223Name: "mutation cfg",
224UpdateStrategy: string(MergeStrategy),
225Containers: []string{"some-ns/some-templ/container_mutated",
226"some-ns/some-templ/some-other-container"},
227},
228},
229templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithContainers},
230want: []util.RenderItem{{
231Render: `spec:
232containers:
233- env:
234- name: ENV_1_ADD
235value: "false"
236- name: ENV_2
237value: "false"
238image: image-1
239name: container_mutated
240`},
241{Render: `spec:
242containers:
243- image: image-2
244name: some-other-container
245resources:
246limits:
247cpu: 51m
248memory: 51Mi
249requests:
250cpu: 50m
251memory: 50Mi
252`}},
253},
254{
255name: "merge_mutation_with_containers_with_intersections",
256args: args{
257config: v1alpha1.MutationConfig{
258Name: "mutation cfg",
259UpdateStrategy: string(MergeStrategy),
260Containers: []string{"some-ns/some-templ/container_mutated",
261"some-ns/some-templ/some-other-container"},
262},
263},
264templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithContainersWithIntersections},
265want: []util.RenderItem{{
266Render: `spec:
267containers:
268- env:
269- name: ENV_1_ADD
270value: "false"
271- name: ENV_2
272value: "false"
273image: image-1
274name: container_mutated
275`},
276{Render: `spec:
277containers:
278- env:
279- name: ENV_1_ADD-REPLACED
280value: false-REPLACED
281- name: ENV_2-REPLACED
282value: false-REPLACED
283image: image-1-REPLACED
284name: container_mutated
285`},
286{Render: `spec:
287containers:
288- image: image-2
289name: some-other-container
290resources:
291limits:
292cpu: 51m
293memory: 51Mi
294requests:
295cpu: 50m
296memory: 50Mi
297`}},
298},
299{
300name: "merge_mutation_with_a_volume",
301args: args{
302config: v1alpha1.MutationConfig{
303Name: "mutation volume",
304UpdateStrategy: string(MergeStrategy),
305Volumes: []string{"some-ns/some-templ/volume_mutated1"},
306},
307},
308templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAVolume},
309want: []util.RenderItem{{
310Render: `spec:
311volumes:
312- configMap:
313name: istio
314name: volume_mutated1
315`}},
316},
317{
318name: "merge_mutation_with_volumes",
319args: args{
320config: v1alpha1.MutationConfig{
321Name: "mutation volume",
322UpdateStrategy: string(MergeStrategy),
323Volumes: []string{"some-ns/some-templ/volume_mutated1", "some-ns/some-templ/volume_mutated2", "some-ns/some-templ/volume_mutated3"},
324},
325},
326templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithVolumes},
327want: []util.RenderItem{{
328Render: `spec:
329volumes:
330- configMap:
331name: istio
332name: volume_mutated1
333`}, {
334Render: `spec:
335volumes:
336- hostPath:
337path: /data
338type: Directory
339name: volume_mutated2
340`}, {
341Render: `spec:
342volumes:
343- name: volume_mutated3
344secret:
345optional: true
346secretName: mysecret
347`}},
348},
349{
350name: "merge_mutation_with_volumes_with_intersections",
351args: args{
352config: v1alpha1.MutationConfig{
353Name: "mutation volume",
354UpdateStrategy: string(MergeStrategy),
355Volumes: []string{"some-ns/some-templ/volume_mutated1", "some-ns/some-templ/volume_mutated2"},
356},
357},
358templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithVolumesWithIntersections},
359want: []util.RenderItem{{
360Render: `spec:
361volumes:
362- configMap:
363name: istio
364name: volume_mutated1
365`}, {
366Render: `spec:
367volumes:
368- configMap:
369name: istio-REPLACED
370name: volume_mutated1
371secret:
372optional: true
373secretName: mysecret
374`}, {
375Render: `spec:
376volumes:
377- hostPath:
378path: /data
379type: Directory
380name: volume_mutated2
381`}},
382},
383{
384name: "merge_mutation_with_an_annotation",
385args: args{
386config: v1alpha1.MutationConfig{
387Name: "mutation annot",
388UpdateStrategy: string(MergeStrategy),
389Annotations: []string{"some-ns/some-templ/annotation_mutated1"},
390},
391},
392templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAnAnnotation},
393want: []util.RenderItem{{
394Render: `metadata:
395annotations:
396annotation_mutated1: val-after-mutation
397`}},
398},
399{
400name: "replace_mutation_with_an_annotation",
401args: args{
402config: v1alpha1.MutationConfig{
403Name: "mutation annot",
404UpdateStrategy: string(ReplaceStrategy),
405Annotations: []string{"some-ns/some-templ/annotation_mutated1"},
406},
407},
408templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAnAnnotation},
409want: []util.RenderItem{{
410Render: `metadata:
411annotations:
412annotation_mutated1: val-after-mutation
413`}},
414},
415{
416name: "merge_mutation_with_annotations",
417args: args{
418config: v1alpha1.MutationConfig{
419Name: "mutation annot",
420UpdateStrategy: string(MergeStrategy),
421Annotations: []string{"some-ns/some-templ/annotation_mutated1",
422"some-ns/some-templ/annotation_mutated2"},
423},
424},
425templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAnnotations},
426want: []util.RenderItem{
427{Render: `metadata:
428annotations:
429annotation_mutated1: val-after-mutation
430`},
431{Render: `metadata:
432annotations:
433annotation_mutated2: another-val-after-mutation
434`}},
435},
436{
437name: "merge_mutation_with_annotations",
438args: args{
439config: v1alpha1.MutationConfig{
440Name: "mutation annot",
441UpdateStrategy: string(ReplaceStrategy),
442Annotations: []string{"some-ns/some-templ/annotation_mutated1",
443"some-ns/some-templ/annotation_mutated2"},
444},
445},
446templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAnnotations},
447want: []util.RenderItem{
448{Render: `metadata:
449annotations:
450annotation_mutated1: val-after-mutation
451`},
452{Render: `metadata:
453annotations:
454annotation_mutated2: another-val-after-mutation
455`}},
456},
457{
458name: "merge_mutation_with_annotations_with_adding",
459args: args{
460obj: map[string]interface{}{"metadata": map[string]interface{}{
461"annotations": map[string]interface{}{
462"annotation_mutated1": "val-after-mutation",
463"annot2": "value2",
464},
465}},
466config: v1alpha1.MutationConfig{
467Name: "mutation annot",
468UpdateStrategy: string(ReplaceStrategy),
469Annotations: []string{"some-ns/some-templ/annotation_mutated1",
470"some-ns/some-templ/annotation_mutated2"},
471},
472},
473templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAnnotations},
474want: []util.RenderItem{
475{Render: `metadata:
476annotations:
477annotation_mutated1: val-after-mutation
478`},
479{Render: `metadata:
480annotations:
481annotation_mutated2: another-val-after-mutation
482`}},
483},
484{
485name: "replace_mutation_adding_container", // replaced container not in obj
486args: args{
487obj: map[string]interface{}{"spec": map[string]interface{}{
488"containers": []interface{}{
489map[string]interface{}{
490"name": "orig_to-test-latte",
491"image": "orig_img",
492"resources": map[string]interface{}{
493"limits": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
494"requests": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
495},
496},
497},
498}},
499config: v1alpha1.MutationConfig{
500Name: "mutation cfg",
501UpdateStrategy: string(ReplaceStrategy),
502Containers: []string{"some-ns/some-templ/container_mutated"},
503},
504},
505templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAContainer},
506want: []util.RenderItem{{Render: `spec:
507containers:
508- image: orig_img
509name: orig_to-test-latte
510resources:
511limits:
512cpu: orig_100m
513memory: orig_100Mi
514requests:
515cpu: orig_100m
516memory: orig_100Mi
517- args:
518- arg1mut
519env:
520- name: env_name_mutated
521value: _mutated
522- name: ENV_10_mutated
523value: _mutated
524image: imagemut
525name: container_mutated
526resources:
527limits:
528cpu: 55_mutated
529memory: 55_mutated
530requests:
531cpu: 55_mutated
532memory: 55_mutated
533securityContext:
534capabilities:
535drop:
536- ALL_mutated
537`}},
538},
539{
540name: "replace_mutation_replacing_container", // replaced container in obj
541args: args{
542obj: map[string]interface{}{"spec": map[string]interface{}{
543"containers": []interface{}{
544map[string]interface{}{
545"name": "container_mutated",
546"image": "orig_img",
547"resources": map[string]interface{}{
548"limits": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
549"requests": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
550},
551},
552},
553}},
554config: v1alpha1.MutationConfig{
555Name: "mutation cfg",
556UpdateStrategy: string(ReplaceStrategy),
557Containers: []string{"some-ns/some-templ/container_mutated"},
558},
559},
560templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAContainer},
561want: []util.RenderItem{{Render: `spec:
562containers:
563- args:
564- arg1mut
565env:
566- name: env_name_mutated
567value: _mutated
568- name: ENV_10_mutated
569value: _mutated
570image: imagemut
571name: container_mutated
572resources:
573limits:
574cpu: 55_mutated
575memory: 55_mutated
576requests:
577cpu: 55_mutated
578memory: 55_mutated
579securityContext:
580capabilities:
581drop:
582- ALL_mutated
583`}},
584},
585{
586name: "replace_mutation_intersection_container", // replaced container in obj
587args: args{
588obj: map[string]interface{}{"spec": map[string]interface{}{
589"containers": []interface{}{
590map[string]interface{}{
591"name": "container_mutated",
592"image": "orig_img",
593"resources": map[string]interface{}{
594"limits": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
595"requests": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
596},
597},
598},
599}},
600config: v1alpha1.MutationConfig{
601Name: "mutation cfg",
602UpdateStrategy: string(ReplaceStrategy),
603Containers: []string{"some-ns/some-templ/container_mutated",
604"some-ns/some-templ/some-other-container"},
605},
606},
607templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithContainersWithIntersections},
608want: []util.RenderItem{{
609Render: `spec:
610containers:
611- env:
612- name: ENV_1_ADD
613value: "false"
614- name: ENV_2
615value: "false"
616image: image-1
617name: container_mutated
618`}, {Render: `spec:
619containers:
620- env:
621- name: ENV_1_ADD-REPLACED
622value: false-REPLACED
623- name: ENV_2-REPLACED
624value: false-REPLACED
625image: image-1-REPLACED
626name: container_mutated
627`}, {Render: `spec:
628containers:
629- env:
630- name: ENV_1_ADD-REPLACED
631value: false-REPLACED
632- name: ENV_2-REPLACED
633value: false-REPLACED
634image: image-1-REPLACED
635name: container_mutated
636- image: image-2
637name: some-other-container
638resources:
639limits:
640cpu: 51m
641memory: 51Mi
642requests:
643cpu: 50m
644memory: 50Mi
645`}},
646},
647{
648name: "replace_mutation_with_a_volume_adding_vol",
649args: args{
650obj: map[string]interface{}{"spec": map[string]interface{}{
651"volumes": []interface{}{
652map[string]interface{}{
653"name": "volume_mutated",
654"image": "orig_img",
655"resources": map[string]interface{}{
656"limits": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
657"requests": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
658},
659},
660},
661}},
662
663config: v1alpha1.MutationConfig{
664Name: "mutation volume",
665UpdateStrategy: string(ReplaceStrategy),
666Volumes: []string{"some-ns/some-templ/volume_mutated1"},
667},
668},
669templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAVolume},
670want: []util.RenderItem{{
671Render: `spec:
672volumes:
673- image: orig_img
674name: volume_mutated
675resources:
676limits:
677cpu: orig_100m
678memory: orig_100Mi
679requests:
680cpu: orig_100m
681memory: orig_100Mi
682- configMap:
683name: istio
684name: volume_mutated1
685`}},
686},
687{
688name: "replace_mutation_with_a_volume_replace_vol",
689args: args{
690obj: map[string]interface{}{"spec": map[string]interface{}{
691"volumes": []interface{}{
692map[string]interface{}{
693"name": "volume_mutated1",
694"image": "orig_img",
695"resources": map[string]interface{}{
696"limits": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
697"requests": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
698},
699},
700},
701}},
702
703config: v1alpha1.MutationConfig{
704Name: "mutation volume",
705UpdateStrategy: string(ReplaceStrategy),
706Volumes: []string{"some-ns/some-templ/volume_mutated1"},
707},
708},
709templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAVolume},
710want: []util.RenderItem{{
711Render: `spec:
712volumes:
713- configMap:
714name: istio
715name: volume_mutated1
716`}},
717},
718{
719name: "replace_mutation_with_a_volume_replace_vol",
720args: args{
721obj: map[string]interface{}{"spec": map[string]interface{}{
722"volumes": []interface{}{
723map[string]interface{}{
724"name": "volume_mutated1",
725"image": "orig_img",
726"resources": map[string]interface{}{
727"limits": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
728"requests": map[string]interface{}{"cpu": "orig_100m", "memory": "orig_100Mi"},
729},
730},
731},
732}},
733
734config: v1alpha1.MutationConfig{
735Name: "mutation volume",
736UpdateStrategy: string(ReplaceStrategy),
737Volumes: []string{"some-ns/some-templ/volume_mutated1"},
738},
739},
740templates: map[string]v1alpha1.Template{"some-ns/some-templ": templateWithAVolumeWithIntersection},
741want: []util.RenderItem{{
742Render: `spec:
743volumes:
744- configMap:
745name: istio
746name: volume_mutated1
747`}, {Render: `spec:
748volumes:
749- configMap:
750name: istio-REPLACED
751name: volume_mutated1
752`}},
753},
754}
755for _, tt := range tests {
756t.Run(tt.name, func(t *testing.T) {
757lib.ZapLogger = zap.NewNop()
758
759rI := NewMutRenderer(baseMatch.NewMatcher(), nil)
760r := rI.(*MutRenderer)
761got := r.getRendersForPod(context.Background(), tt.templates, tt.args.obj, tt.args.config)
762
763if len(got) != len(tt.want) {
764t.Fatalf("len got = %v, len want = %v.\ngot: %v\n",
765len(got), len(tt.want), got)
766}
767
768for i := range got {
769if !reflect.DeepEqual(got[i].Render, tt.want[i].Render) {
770t.Errorf("getRendersForPod()[%v].Render = \n%+v, want \n%+v", i, got[i].Render, tt.want[i].Render)
771}
772}
773})
774}
775}
776
777func Test_convert(t *testing.T) {
778type args struct {
779i interface{}
780}
781tests := []struct {
782name string
783args args
784want interface{}
785}{
786{
787name: "map string interface",
788args: args{
789i: map[string]interface{}{
790"metadata": map[string]interface{}{
791"test": "value",
792},
793},
794},
795want: map[string]interface{}{
796"metadata": map[string]interface{}{
797"test": "value",
798},
799},
800},
801{
802name: "map slice of interfaces",
803args: args{
804i: []interface{}{
805map[string]string{
806"test": "value",
807},
808},
809},
810want: []interface{}{
811map[string]string{"test": "value"},
812},
813},
814}
815for _, tt := range tests {
816t.Run(tt.name, func(t *testing.T) {
817if got := convert(tt.args.i); !reflect.DeepEqual(got, tt.want) {
818t.Errorf("convert() = %v, want %v", got, tt.want)
819}
820})
821}
822}
823