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  }