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  }