sigs.k8s.io/cluster-api-provider-azure@v1.17.0/pkg/mutators/mutator_test.go (about) 1 /* 2 Copyright 2024 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package mutators 18 19 import ( 20 "context" 21 "errors" 22 "testing" 23 24 asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001" 25 "github.com/Azure/azure-service-operator/v2/pkg/common/annotations" 26 . "github.com/onsi/gomega" 27 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 28 "k8s.io/apimachinery/pkg/runtime" 29 "sigs.k8s.io/controller-runtime/pkg/reconcile" 30 ) 31 32 func TestApplyMutators(t *testing.T) { 33 ctx := context.Background() 34 35 tests := []struct { 36 name string 37 resources []runtime.RawExtension 38 mutators []ResourcesMutator 39 expected []*unstructured.Unstructured 40 expectedErr error 41 }{ 42 { 43 name: "no mutators", 44 resources: []runtime.RawExtension{ 45 {Raw: []byte(`{"apiVersion": "v1", "kind": "SomeObject"}`)}, 46 }, 47 expected: []*unstructured.Unstructured{ 48 {Object: map[string]interface{}{"apiVersion": "v1", "kind": "SomeObject"}}, 49 }, 50 }, 51 { 52 name: "mutators apply in order", 53 resources: []runtime.RawExtension{ 54 {Raw: []byte(`{"apiVersion": "v1", "kind": "SomeObject"}`)}, 55 }, 56 mutators: []ResourcesMutator{ 57 func(_ context.Context, us []*unstructured.Unstructured) error { 58 us[0].Object["f1"] = "3" 59 us[0].Object["f2"] = "3" 60 us[0].Object["f3"] = "3" 61 return nil 62 }, 63 func(_ context.Context, us []*unstructured.Unstructured) error { 64 us[0].Object["f1"] = "2" 65 us[0].Object["f2"] = "2" 66 return nil 67 }, 68 func(_ context.Context, us []*unstructured.Unstructured) error { 69 us[0].Object["f1"] = "1" 70 return nil 71 }, 72 }, 73 expected: []*unstructured.Unstructured{ 74 { 75 Object: map[string]interface{}{ 76 "apiVersion": "v1", 77 "kind": "SomeObject", 78 "f1": "1", 79 "f2": "2", 80 "f3": "3", 81 }, 82 }, 83 }, 84 }, 85 { 86 name: "error", 87 resources: []runtime.RawExtension{}, 88 mutators: []ResourcesMutator{ 89 func(_ context.Context, us []*unstructured.Unstructured) error { 90 return errors.New("mutator err") 91 }, 92 }, 93 expectedErr: errors.New("mutator err"), 94 }, 95 { 96 name: "incompatible is terminal", 97 resources: []runtime.RawExtension{}, 98 mutators: []ResourcesMutator{ 99 func(_ context.Context, us []*unstructured.Unstructured) error { 100 return Incompatible{} 101 }, 102 }, 103 expectedErr: reconcile.TerminalError(Incompatible{}), 104 }, 105 } 106 107 for _, test := range tests { 108 t.Run(test.name, func(t *testing.T) { 109 g := NewGomegaWithT(t) 110 111 actual, err := ApplyMutators(ctx, test.resources, test.mutators...) 112 if test.expectedErr != nil { 113 g.Expect(err).To(MatchError(test.expectedErr)) 114 } else { 115 g.Expect(err).NotTo(HaveOccurred()) 116 } 117 g.Expect(actual).To(Equal(test.expected)) 118 }) 119 } 120 } 121 122 func TestPause(t *testing.T) { 123 ctx := context.Background() 124 125 tests := []struct { 126 name string 127 policy string 128 isIncompatible bool 129 }{ 130 { 131 name: "set from CAPI opinion", 132 policy: "", 133 }, 134 { 135 name: "user value matching CAPI ok", 136 policy: string(annotations.ReconcilePolicySkip), 137 }, 138 { 139 name: "incompatible", 140 policy: string(annotations.ReconcilePolicyManage), 141 isIncompatible: true, 142 }, 143 } 144 145 s := runtime.NewScheme() 146 NewGomegaWithT(t).Expect(asocontainerservicev1.AddToScheme(s)).To(Succeed()) 147 148 for _, test := range tests { 149 t.Run(test.name, func(t *testing.T) { 150 g := NewGomegaWithT(t) 151 152 u := &unstructured.Unstructured{} 153 if test.policy != "" { 154 u.SetAnnotations(map[string]string{ 155 annotations.ReconcilePolicy: test.policy, 156 }) 157 } 158 err := Pause(ctx, []*unstructured.Unstructured{u}) 159 if test.isIncompatible { 160 g.Expect(errors.As(err, &Incompatible{})).To(BeTrue()) 161 } else { 162 g.Expect(err).NotTo(HaveOccurred()) 163 g.Expect(u.GetAnnotations()).To(HaveKeyWithValue(annotations.ReconcilePolicy, string(annotations.ReconcilePolicySkip))) 164 } 165 }) 166 } 167 }