sigs.k8s.io/cluster-api-provider-azure@v1.14.3/exp/controllers/azuremachinepoolmachine_controller_test.go (about) 1 /* 2 Copyright 2020 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 controllers 18 19 import ( 20 "context" 21 "testing" 22 "time" 23 24 . "github.com/onsi/gomega" 25 "go.uber.org/mock/gomock" 26 corev1 "k8s.io/api/core/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/runtime" 29 "k8s.io/apimachinery/pkg/types" 30 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 31 "sigs.k8s.io/cluster-api-provider-azure/azure" 32 "sigs.k8s.io/cluster-api-provider-azure/azure/mock_azure" 33 "sigs.k8s.io/cluster-api-provider-azure/azure/scope" 34 infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1" 35 gomock2 "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" 36 reconcilerutils "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" 37 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 38 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 39 ctrl "sigs.k8s.io/controller-runtime" 40 "sigs.k8s.io/controller-runtime/pkg/client" 41 "sigs.k8s.io/controller-runtime/pkg/client/fake" 42 ) 43 44 func TestAzureMachinePoolMachineReconciler_Reconcile(t *testing.T) { 45 cases := []struct { 46 Name string 47 Setup func(cb *fake.ClientBuilder, reconciler *mock_azure.MockReconcilerMockRecorder) 48 Verify func(g *WithT, result ctrl.Result, err error) 49 }{ 50 { 51 Name: "should successfully reconcile", 52 Setup: func(cb *fake.ClientBuilder, reconciler *mock_azure.MockReconcilerMockRecorder) { 53 objects := getReadyMachinePoolMachineClusterObjects(false) 54 reconciler.Reconcile(gomock2.AContext()).Return(nil) 55 cb.WithObjects(objects...) 56 }, 57 Verify: func(g *WithT, result ctrl.Result, err error) { 58 g.Expect(err).NotTo(HaveOccurred()) 59 }, 60 }, 61 { 62 Name: "should successfully delete", 63 Setup: func(cb *fake.ClientBuilder, reconciler *mock_azure.MockReconcilerMockRecorder) { 64 objects := getReadyMachinePoolMachineClusterObjects(true) 65 reconciler.Delete(gomock2.AContext()).Return(nil) 66 cb.WithObjects(objects...) 67 }, 68 Verify: func(g *WithT, result ctrl.Result, err error) { 69 g.Expect(err).NotTo(HaveOccurred()) 70 }, 71 }, 72 } 73 74 for _, c := range cases { 75 c := c 76 t.Run(c.Name, func(t *testing.T) { 77 var ( 78 g = NewWithT(t) 79 mockCtrl = gomock.NewController(t) 80 reconciler = mock_azure.NewMockReconciler(mockCtrl) 81 scheme = func() *runtime.Scheme { 82 s := runtime.NewScheme() 83 for _, addTo := range []func(s *runtime.Scheme) error{ 84 clusterv1.AddToScheme, 85 expv1.AddToScheme, 86 infrav1.AddToScheme, 87 infrav1exp.AddToScheme, 88 corev1.AddToScheme, 89 } { 90 g.Expect(addTo(s)).To(Succeed()) 91 } 92 93 return s 94 }() 95 cb = fake.NewClientBuilder().WithScheme(scheme) 96 ) 97 defer mockCtrl.Finish() 98 99 c.Setup(cb, reconciler.EXPECT()) 100 controller := NewAzureMachinePoolMachineController(cb.Build(), nil, reconcilerutils.Timeouts{}, "foo") 101 controller.reconcilerFactory = func(_ *scope.MachinePoolMachineScope) (azure.Reconciler, error) { 102 return reconciler, nil 103 } 104 res, err := controller.Reconcile(context.TODO(), ctrl.Request{ 105 NamespacedName: types.NamespacedName{ 106 Name: "ampm1", 107 Namespace: "default", 108 }, 109 }) 110 c.Verify(g, res, err) 111 }) 112 } 113 } 114 115 func getReadyMachinePoolMachineClusterObjects(ampmIsDeleting bool) []client.Object { 116 azCluster := &infrav1.AzureCluster{ 117 TypeMeta: metav1.TypeMeta{ 118 Kind: "AzureCluster", 119 }, 120 ObjectMeta: metav1.ObjectMeta{ 121 Name: "azCluster1", 122 Namespace: "default", 123 }, 124 Spec: infrav1.AzureClusterSpec{ 125 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 126 SubscriptionID: "subID", 127 IdentityRef: &corev1.ObjectReference{ 128 Name: "fake-identity", 129 Namespace: "default", 130 Kind: "AzureClusterIdentity", 131 }, 132 }, 133 }, 134 } 135 136 cluster := &clusterv1.Cluster{ 137 TypeMeta: metav1.TypeMeta{ 138 Kind: "Cluster", 139 }, 140 ObjectMeta: metav1.ObjectMeta{ 141 Name: "cluster1", 142 Namespace: "default", 143 }, 144 Spec: clusterv1.ClusterSpec{ 145 InfrastructureRef: &corev1.ObjectReference{ 146 Name: azCluster.Name, 147 Namespace: "default", 148 Kind: "AzureCluster", 149 }, 150 }, 151 Status: clusterv1.ClusterStatus{ 152 InfrastructureReady: true, 153 }, 154 } 155 156 mp := &expv1.MachinePool{ 157 TypeMeta: metav1.TypeMeta{ 158 Kind: "MachinePool", 159 }, 160 ObjectMeta: metav1.ObjectMeta{ 161 Name: "mp1", 162 Namespace: "default", 163 Labels: map[string]string{ 164 "cluster.x-k8s.io/cluster-name": cluster.Name, 165 }, 166 }, 167 } 168 169 amp := &infrav1exp.AzureMachinePool{ 170 TypeMeta: metav1.TypeMeta{ 171 Kind: "AzureMachinePool", 172 }, 173 ObjectMeta: metav1.ObjectMeta{ 174 Name: "amp1", 175 Namespace: "default", 176 OwnerReferences: []metav1.OwnerReference{ 177 { 178 Name: mp.Name, 179 Kind: "MachinePool", 180 APIVersion: expv1.GroupVersion.String(), 181 }, 182 }, 183 }, 184 } 185 186 ma := &clusterv1.Machine{ 187 ObjectMeta: metav1.ObjectMeta{ 188 Name: "ma1", 189 Namespace: "default", 190 OwnerReferences: []metav1.OwnerReference{ 191 { 192 Name: mp.Name, 193 Kind: "MachinePool", 194 APIVersion: expv1.GroupVersion.String(), 195 }, 196 }, 197 Labels: map[string]string{ 198 "cluster.x-k8s.io/cluster-name": cluster.Name, 199 }, 200 }, 201 } 202 203 ampm := &infrav1exp.AzureMachinePoolMachine{ 204 ObjectMeta: metav1.ObjectMeta{ 205 Name: "ampm1", 206 Namespace: "default", 207 Finalizers: []string{"test"}, 208 Labels: map[string]string{ 209 clusterv1.ClusterNameLabel: cluster.Name, 210 }, 211 OwnerReferences: []metav1.OwnerReference{ 212 { 213 Name: amp.Name, 214 Kind: infrav1.AzureMachinePoolKind, 215 APIVersion: infrav1exp.GroupVersion.String(), 216 }, 217 { 218 Name: ma.Name, 219 Kind: "Machine", 220 APIVersion: clusterv1.GroupVersion.String(), 221 }, 222 }, 223 }, 224 } 225 226 fakeIdentity := &infrav1.AzureClusterIdentity{ 227 ObjectMeta: metav1.ObjectMeta{ 228 Name: "fake-identity", 229 Namespace: "default", 230 }, 231 Spec: infrav1.AzureClusterIdentitySpec{ 232 Type: infrav1.ServicePrincipal, 233 ClientSecret: corev1.SecretReference{ 234 Name: "fooSecret", 235 Namespace: "default", 236 }, 237 TenantID: "fake-tenantid", 238 }, 239 } 240 241 fakeSecret := &corev1.Secret{ 242 ObjectMeta: metav1.ObjectMeta{ 243 Name: "fooSecret", 244 Namespace: "default", 245 }, 246 Data: map[string][]byte{ 247 "clientSecret": []byte("fooSecret"), 248 }, 249 } 250 251 if ampmIsDeleting { 252 ampm.DeletionTimestamp = &metav1.Time{ 253 Time: time.Now(), 254 } 255 } 256 257 return []client.Object{cluster, azCluster, mp, amp, ma, ampm, fakeIdentity, fakeSecret} 258 }