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