sigs.k8s.io/cluster-api-provider-azure@v1.14.3/exp/controllers/azuremachinepool_reconciler_test.go (about) 1 /* 2 Copyright 2022 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 "errors" 22 "testing" 23 24 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" 25 . "github.com/onsi/gomega" 26 "go.uber.org/mock/gomock" 27 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 28 "sigs.k8s.io/cluster-api-provider-azure/azure" 29 "sigs.k8s.io/cluster-api-provider-azure/azure/mock_azure" 30 "sigs.k8s.io/cluster-api-provider-azure/azure/scope" 31 "sigs.k8s.io/cluster-api-provider-azure/azure/services/resourceskus" 32 infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1" 33 gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" 34 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 35 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 36 ) 37 38 func TestAzureMachinePoolServiceReconcile(t *testing.T) { 39 cases := map[string]struct { 40 expectedError string 41 expect func(one *mock_azure.MockServiceReconcilerMockRecorder, two *mock_azure.MockServiceReconcilerMockRecorder, three *mock_azure.MockServiceReconcilerMockRecorder) 42 }{ 43 "all services are reconciled in order": { 44 expectedError: "", 45 expect: func(one *mock_azure.MockServiceReconcilerMockRecorder, two *mock_azure.MockServiceReconcilerMockRecorder, three *mock_azure.MockServiceReconcilerMockRecorder) { 46 gomock.InOrder( 47 one.Reconcile(gomockinternal.AContext()).Return(nil), 48 two.Reconcile(gomockinternal.AContext()).Return(nil), 49 three.Reconcile(gomockinternal.AContext()).Return(nil)) 50 }, 51 }, 52 "service reconcile fails": { 53 expectedError: "failed to reconcile AzureMachinePool service foo: some error happened", 54 expect: func(one *mock_azure.MockServiceReconcilerMockRecorder, two *mock_azure.MockServiceReconcilerMockRecorder, three *mock_azure.MockServiceReconcilerMockRecorder) { 55 gomock.InOrder( 56 one.Reconcile(gomockinternal.AContext()).Return(nil), 57 two.Reconcile(gomockinternal.AContext()).Return(errors.New("some error happened")), 58 two.Name().Return("foo")) 59 }, 60 }, 61 } 62 63 for name, tc := range cases { 64 tc := tc 65 t.Run(name, func(t *testing.T) { 66 g := NewWithT(t) 67 68 t.Parallel() 69 mockCtrl := gomock.NewController(t) 70 defer mockCtrl.Finish() 71 svcOneMock := mock_azure.NewMockServiceReconciler(mockCtrl) 72 svcTwoMock := mock_azure.NewMockServiceReconciler(mockCtrl) 73 svcThreeMock := mock_azure.NewMockServiceReconciler(mockCtrl) 74 75 tc.expect(svcOneMock.EXPECT(), svcTwoMock.EXPECT(), svcThreeMock.EXPECT()) 76 77 s := &azureMachinePoolService{ 78 scope: &scope.MachinePoolScope{ 79 ClusterScoper: &scope.ClusterScope{ 80 AzureCluster: &infrav1.AzureCluster{}, 81 Cluster: &clusterv1.Cluster{}, 82 }, 83 MachinePool: &expv1.MachinePool{}, 84 AzureMachinePool: &infrav1exp.AzureMachinePool{ 85 Spec: infrav1exp.AzureMachinePoolSpec{ 86 Template: infrav1exp.AzureMachinePoolMachineTemplate{ 87 SubnetName: "test-subnet", 88 }, 89 }, 90 }, 91 }, 92 services: []azure.ServiceReconciler{ 93 svcOneMock, 94 svcTwoMock, 95 svcThreeMock, 96 }, 97 skuCache: resourceskus.NewStaticCache([]armcompute.ResourceSKU{}, ""), 98 } 99 100 err := s.Reconcile(context.TODO()) 101 if tc.expectedError != "" { 102 g.Expect(err).To(HaveOccurred()) 103 g.Expect(err).To(MatchError(tc.expectedError)) 104 } else { 105 g.Expect(err).NotTo(HaveOccurred()) 106 } 107 }) 108 } 109 } 110 111 func TestAzureMachinePoolServicePause(t *testing.T) { 112 type pausingServiceReconciler struct { 113 *mock_azure.MockServiceReconciler 114 *mock_azure.MockPauser 115 } 116 117 cases := map[string]struct { 118 expectedError string 119 expect func(one pausingServiceReconciler, two pausingServiceReconciler, three pausingServiceReconciler) 120 }{ 121 "all services are paused in order": { 122 expectedError: "", 123 expect: func(one pausingServiceReconciler, two pausingServiceReconciler, three pausingServiceReconciler) { 124 gomock.InOrder( 125 one.MockPauser.EXPECT().Pause(gomockinternal.AContext()).Return(nil), 126 two.MockPauser.EXPECT().Pause(gomockinternal.AContext()).Return(nil), 127 three.MockPauser.EXPECT().Pause(gomockinternal.AContext()).Return(nil)) 128 }, 129 }, 130 "service pause fails": { 131 expectedError: "failed to pause AzureMachinePool service two: some error happened", 132 expect: func(one pausingServiceReconciler, two pausingServiceReconciler, _ pausingServiceReconciler) { 133 gomock.InOrder( 134 one.MockPauser.EXPECT().Pause(gomockinternal.AContext()).Return(nil), 135 two.MockPauser.EXPECT().Pause(gomockinternal.AContext()).Return(errors.New("some error happened")), 136 two.MockServiceReconciler.EXPECT().Name().Return("two")) 137 }, 138 }, 139 } 140 141 for name, tc := range cases { 142 tc := tc 143 t.Run(name, func(t *testing.T) { 144 g := NewWithT(t) 145 146 t.Parallel() 147 mockCtrl := gomock.NewController(t) 148 defer mockCtrl.Finish() 149 150 newPausingServiceReconciler := func() pausingServiceReconciler { 151 return pausingServiceReconciler{ 152 mock_azure.NewMockServiceReconciler(mockCtrl), 153 mock_azure.NewMockPauser(mockCtrl), 154 } 155 } 156 svcOneMock := newPausingServiceReconciler() 157 svcTwoMock := newPausingServiceReconciler() 158 svcThreeMock := newPausingServiceReconciler() 159 160 tc.expect(svcOneMock, svcTwoMock, svcThreeMock) 161 162 s := &azureMachinePoolService{ 163 services: []azure.ServiceReconciler{ 164 svcOneMock, 165 svcTwoMock, 166 svcThreeMock, 167 }, 168 } 169 170 err := s.Pause(context.TODO()) 171 if tc.expectedError != "" { 172 g.Expect(err).To(HaveOccurred()) 173 g.Expect(err).To(MatchError(tc.expectedError)) 174 } else { 175 g.Expect(err).NotTo(HaveOccurred()) 176 } 177 }) 178 } 179 } 180 181 func TestAzureMachinePoolServiceDelete(t *testing.T) { 182 cases := map[string]struct { 183 expectedError string 184 expect func(one *mock_azure.MockServiceReconcilerMockRecorder, two *mock_azure.MockServiceReconcilerMockRecorder, three *mock_azure.MockServiceReconcilerMockRecorder) 185 }{ 186 "all services deleted in order": { 187 expectedError: "", 188 expect: func(one *mock_azure.MockServiceReconcilerMockRecorder, two *mock_azure.MockServiceReconcilerMockRecorder, three *mock_azure.MockServiceReconcilerMockRecorder) { 189 gomock.InOrder( 190 three.Delete(gomockinternal.AContext()).Return(nil), 191 two.Delete(gomockinternal.AContext()).Return(nil), 192 one.Delete(gomockinternal.AContext()).Return(nil)) 193 }, 194 }, 195 "service delete fails": { 196 expectedError: "failed to delete AzureMachinePool service test-service-two: some error happened", 197 expect: func(one *mock_azure.MockServiceReconcilerMockRecorder, two *mock_azure.MockServiceReconcilerMockRecorder, three *mock_azure.MockServiceReconcilerMockRecorder) { 198 gomock.InOrder( 199 three.Delete(gomockinternal.AContext()).Return(nil), 200 two.Delete(gomockinternal.AContext()).Return(errors.New("some error happened")), 201 two.Name().Return("test-service-two")) 202 }, 203 }, 204 } 205 206 for name, tc := range cases { 207 tc := tc 208 t.Run(name, func(t *testing.T) { 209 g := NewWithT(t) 210 211 t.Parallel() 212 mockCtrl := gomock.NewController(t) 213 defer mockCtrl.Finish() 214 svcOneMock := mock_azure.NewMockServiceReconciler(mockCtrl) 215 svcTwoMock := mock_azure.NewMockServiceReconciler(mockCtrl) 216 svcThreeMock := mock_azure.NewMockServiceReconciler(mockCtrl) 217 218 tc.expect(svcOneMock.EXPECT(), svcTwoMock.EXPECT(), svcThreeMock.EXPECT()) 219 220 s := &azureMachinePoolService{ 221 scope: &scope.MachinePoolScope{ 222 ClusterScoper: &scope.ClusterScope{ 223 AzureCluster: &infrav1.AzureCluster{}, 224 Cluster: &clusterv1.Cluster{}, 225 }, 226 MachinePool: &expv1.MachinePool{}, 227 AzureMachinePool: &infrav1exp.AzureMachinePool{}, 228 }, 229 services: []azure.ServiceReconciler{ 230 svcOneMock, 231 svcTwoMock, 232 svcThreeMock, 233 }, 234 skuCache: resourceskus.NewStaticCache([]armcompute.ResourceSKU{}, ""), 235 } 236 237 err := s.Delete(context.TODO()) 238 if tc.expectedError != "" { 239 g.Expect(err).To(HaveOccurred()) 240 g.Expect(err).To(MatchError(tc.expectedError)) 241 } else { 242 g.Expect(err).NotTo(HaveOccurred()) 243 } 244 }) 245 } 246 }