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  }