sigs.k8s.io/cluster-api-provider-azure@v1.14.3/exp/controllers/helpers_test.go (about)

     1  /*
     2  Copyright 2019 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  
    23  	"github.com/go-logr/logr"
    24  	. "github.com/onsi/gomega"
    25  	"go.uber.org/mock/gomock"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/apimachinery/pkg/types"
    29  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    30  	infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1"
    31  	gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock"
    32  	"sigs.k8s.io/cluster-api-provider-azure/internal/test/mock_log"
    33  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    34  	"sigs.k8s.io/controller-runtime/pkg/client"
    35  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    36  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    37  )
    38  
    39  var (
    40  	clusterName = "my-cluster"
    41  )
    42  
    43  func TestAzureClusterToAzureMachinePoolsMapper(t *testing.T) {
    44  	g := NewWithT(t)
    45  	scheme := newScheme(g)
    46  	initObjects := []runtime.Object{
    47  		newCluster(clusterName),
    48  		// Create two Machines with an infrastructure ref and one without.
    49  		newMachinePoolWithInfrastructureRef(clusterName, "my-machine-0"),
    50  		newMachinePoolWithInfrastructureRef(clusterName, "my-machine-1"),
    51  		newMachinePool(clusterName, "my-machine-2"),
    52  	}
    53  	fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build()
    54  
    55  	sink := mock_log.NewMockLogSink(gomock.NewController(t))
    56  	sink.EXPECT().Init(logr.RuntimeInfo{CallDepth: 1})
    57  	sink.EXPECT().Enabled(4).Return(true)
    58  	sink.EXPECT().WithValues("AzureCluster", "my-cluster", "Namespace", "default").Return(sink)
    59  	sink.EXPECT().Info(4, "gk does not match", "gk", gomock.Any(), "infraGK", gomock.Any())
    60  	mapper, err := AzureClusterToAzureMachinePoolsMapper(context.Background(), fakeClient, scheme, logr.New(sink))
    61  	g.Expect(err).NotTo(HaveOccurred())
    62  
    63  	requests := mapper(context.Background(), &infrav1.AzureCluster{
    64  		ObjectMeta: metav1.ObjectMeta{
    65  			Name:      clusterName,
    66  			Namespace: "default",
    67  			OwnerReferences: []metav1.OwnerReference{
    68  				{
    69  					Name:       clusterName,
    70  					Kind:       "Cluster",
    71  					APIVersion: clusterv1.GroupVersion.String(),
    72  				},
    73  			},
    74  		},
    75  	})
    76  	g.Expect(requests).To(HaveLen(2))
    77  }
    78  
    79  func Test_MachinePoolToInfrastructureMapFunc(t *testing.T) {
    80  	cases := []struct {
    81  		Name             string
    82  		Setup            func(logMock *mock_log.MockLogSink)
    83  		MapObjectFactory func(*GomegaWithT) client.Object
    84  		Expect           func(*GomegaWithT, []reconcile.Request)
    85  	}{
    86  		{
    87  			Name: "MachinePoolToAzureMachinePool",
    88  			MapObjectFactory: func(g *GomegaWithT) client.Object {
    89  				return newMachinePoolWithInfrastructureRef("azureCluster", "machinePool")
    90  			},
    91  			Setup: func(logMock *mock_log.MockLogSink) {
    92  				logMock.EXPECT().Init(logr.RuntimeInfo{CallDepth: 1})
    93  			},
    94  			Expect: func(g *GomegaWithT, reqs []reconcile.Request) {
    95  				g.Expect(reqs).To(HaveLen(1))
    96  				g.Expect(reqs[0]).To(Equal(reconcile.Request{
    97  					NamespacedName: types.NamespacedName{
    98  						Name:      "azuremachinePool",
    99  						Namespace: "default",
   100  					},
   101  				}))
   102  			},
   103  		},
   104  		{
   105  			Name: "MachinePoolWithoutMatchingInfraRef",
   106  			MapObjectFactory: func(g *GomegaWithT) client.Object {
   107  				return newMachinePool("azureCluster", "machinePool")
   108  			},
   109  			Setup: func(logMock *mock_log.MockLogSink) {
   110  				ampGK := infrav1exp.GroupVersion.WithKind(infrav1.AzureMachinePoolKind).GroupKind()
   111  				logMock.EXPECT().Init(logr.RuntimeInfo{CallDepth: 1})
   112  				logMock.EXPECT().Enabled(4).Return(true)
   113  				logMock.EXPECT().Info(4, "gk does not match", "gk", ampGK, "infraGK", gomock.Any())
   114  			},
   115  			Expect: func(g *GomegaWithT, reqs []reconcile.Request) {
   116  				g.Expect(reqs).To(BeEmpty())
   117  			},
   118  		},
   119  		{
   120  			Name: "NotAMachinePool",
   121  			MapObjectFactory: func(g *GomegaWithT) client.Object {
   122  				return newCluster("azureCluster")
   123  			},
   124  			Setup: func(logMock *mock_log.MockLogSink) {
   125  				logMock.EXPECT().Init(logr.RuntimeInfo{CallDepth: 1})
   126  				logMock.EXPECT().Enabled(4).Return(true)
   127  				logMock.EXPECT().Info(4, "attempt to map incorrect type", "type", "*v1beta1.Cluster")
   128  			},
   129  			Expect: func(g *GomegaWithT, reqs []reconcile.Request) {
   130  				g.Expect(reqs).To(BeEmpty())
   131  			},
   132  		},
   133  	}
   134  
   135  	for _, c := range cases {
   136  		c := c
   137  		t.Run(c.Name, func(t *testing.T) {
   138  			g := NewWithT(t)
   139  
   140  			mockCtrl := gomock.NewController(t)
   141  			defer mockCtrl.Finish()
   142  
   143  			sink := mock_log.NewMockLogSink(mockCtrl)
   144  			if c.Setup != nil {
   145  				c.Setup(sink)
   146  			}
   147  			f := MachinePoolToInfrastructureMapFunc(infrav1exp.GroupVersion.WithKind(infrav1.AzureMachinePoolKind), logr.New(sink))
   148  			reqs := f(context.TODO(), c.MapObjectFactory(g))
   149  			c.Expect(g, reqs)
   150  		})
   151  	}
   152  }
   153  
   154  func Test_azureClusterToAzureMachinePoolsFunc(t *testing.T) {
   155  	cases := []struct {
   156  		Name             string
   157  		Setup            func(*testing.T, *GomegaWithT) (*mock_log.MockLogSink, *gomock.Controller, client.Client)
   158  		MapObjectFactory func(*GomegaWithT) client.Object
   159  		Expect           func(*GomegaWithT, []reconcile.Request)
   160  	}{
   161  		{
   162  			Name: "NotAnAzureCluster",
   163  			MapObjectFactory: func(g *GomegaWithT) client.Object {
   164  				return newMachinePool("fakeCluster", "bar")
   165  			},
   166  			Setup: func(t *testing.T, g *GomegaWithT) (*mock_log.MockLogSink, *gomock.Controller, client.Client) {
   167  				t.Helper()
   168  				mockCtrl := gomock.NewController(t)
   169  				sink := mock_log.NewMockLogSink(mockCtrl)
   170  				fakeClient := fake.NewClientBuilder().WithScheme(newScheme(g)).Build()
   171  				sink.EXPECT().Init(logr.RuntimeInfo{CallDepth: 1})
   172  				sink.EXPECT().Error(gomockinternal.ErrStrEq("expected a AzureCluster but got a *v1beta1.MachinePool"), "failed to get AzureCluster")
   173  
   174  				return sink, mockCtrl, fakeClient
   175  			},
   176  			Expect: func(g *GomegaWithT, reqs []reconcile.Request) {
   177  				g.Expect(reqs).To(BeEmpty())
   178  			},
   179  		},
   180  		{
   181  			Name: "AzureClusterDoesNotExist",
   182  			MapObjectFactory: func(g *GomegaWithT) client.Object {
   183  				return newAzureCluster("foo")
   184  			},
   185  			Setup: func(t *testing.T, g *GomegaWithT) (*mock_log.MockLogSink, *gomock.Controller, client.Client) {
   186  				t.Helper()
   187  				mockCtrl := gomock.NewController(t)
   188  				sink := mock_log.NewMockLogSink(mockCtrl)
   189  				fakeClient := fake.NewClientBuilder().WithScheme(newScheme(g)).Build()
   190  				sink.EXPECT().Init(logr.RuntimeInfo{CallDepth: 1})
   191  				sink.EXPECT().Enabled(4).Return(true)
   192  				sink.EXPECT().WithValues("AzureCluster", "azurefoo", "Namespace", "default").Return(sink)
   193  				sink.EXPECT().Info(4, "owning cluster not found")
   194  				return sink, mockCtrl, fakeClient
   195  			},
   196  			Expect: func(g *GomegaWithT, reqs []reconcile.Request) {
   197  				g.Expect(reqs).To(BeEmpty())
   198  			},
   199  		},
   200  		{
   201  			Name: "AzureClusterExistsButDoesNotHaveMachinePools",
   202  			MapObjectFactory: func(g *GomegaWithT) client.Object {
   203  				return newAzureCluster("foo")
   204  			},
   205  			Setup: func(t *testing.T, g *GomegaWithT) (*mock_log.MockLogSink, *gomock.Controller, client.Client) {
   206  				t.Helper()
   207  				mockCtrl := gomock.NewController(t)
   208  				sink := mock_log.NewMockLogSink(mockCtrl)
   209  				logWithValues := mock_log.NewMockLogSink(mockCtrl)
   210  				const clusterName = "foo"
   211  				initObj := []runtime.Object{
   212  					newCluster(clusterName),
   213  					newAzureCluster(clusterName),
   214  				}
   215  				fakeClient := fake.NewClientBuilder().WithScheme(newScheme(g)).WithRuntimeObjects(initObj...).Build()
   216  				sink.EXPECT().Init(logr.RuntimeInfo{CallDepth: 1})
   217  				sink.EXPECT().WithValues("AzureCluster", "azurefoo", "Namespace", "default").Return(logWithValues)
   218  				return sink, mockCtrl, fakeClient
   219  			},
   220  			Expect: func(g *GomegaWithT, reqs []reconcile.Request) {
   221  				g.Expect(reqs).To(BeEmpty())
   222  			},
   223  		},
   224  		{
   225  			Name: "AzureClusterExistsWithMachinePoolsButNoInfraRefs",
   226  			MapObjectFactory: func(g *GomegaWithT) client.Object {
   227  				return newAzureCluster("foo")
   228  			},
   229  			Setup: func(t *testing.T, g *GomegaWithT) (*mock_log.MockLogSink, *gomock.Controller, client.Client) {
   230  				t.Helper()
   231  				mockCtrl := gomock.NewController(t)
   232  				sink := mock_log.NewMockLogSink(mockCtrl)
   233  				logWithValues := mock_log.NewMockLogSink(mockCtrl)
   234  				const clusterName = "foo"
   235  				initObj := []runtime.Object{
   236  					newCluster(clusterName),
   237  					newAzureCluster(clusterName),
   238  					newMachinePool(clusterName, "pool1"),
   239  					newMachinePool(clusterName, "pool2"),
   240  				}
   241  				fakeClient := fake.NewClientBuilder().WithScheme(newScheme(g)).WithRuntimeObjects(initObj...).Build()
   242  				sink.EXPECT().Init(logr.RuntimeInfo{CallDepth: 1})
   243  				sink.EXPECT().WithValues("AzureCluster", "azurefoo", "Namespace", "default").Return(logWithValues)
   244  				return sink, mockCtrl, fakeClient
   245  			},
   246  			Expect: func(g *GomegaWithT, reqs []reconcile.Request) {
   247  				g.Expect(reqs).To(BeEmpty())
   248  			},
   249  		},
   250  		{
   251  			Name: "AzureClusterExistsWithMachinePoolsWithOneInfraRefs",
   252  			MapObjectFactory: func(g *GomegaWithT) client.Object {
   253  				return newAzureCluster("foo")
   254  			},
   255  			Setup: func(t *testing.T, g *GomegaWithT) (*mock_log.MockLogSink, *gomock.Controller, client.Client) {
   256  				t.Helper()
   257  				mockCtrl := gomock.NewController(t)
   258  				sink := mock_log.NewMockLogSink(mockCtrl)
   259  				logWithValues := mock_log.NewMockLogSink(mockCtrl)
   260  				const clusterName = "foo"
   261  				initObj := []runtime.Object{
   262  					newCluster(clusterName),
   263  					newAzureCluster(clusterName),
   264  					newMachinePool(clusterName, "pool1"),
   265  					newAzureMachinePool(clusterName, "azurepool2"),
   266  					newMachinePoolWithInfrastructureRef(clusterName, "pool2"),
   267  				}
   268  				fakeClient := fake.NewClientBuilder().WithScheme(newScheme(g)).WithRuntimeObjects(initObj...).Build()
   269  				sink.EXPECT().Init(logr.RuntimeInfo{CallDepth: 1})
   270  				sink.EXPECT().WithValues("AzureCluster", "azurefoo", "Namespace", "default").Return(logWithValues)
   271  				return sink, mockCtrl, fakeClient
   272  			},
   273  			Expect: func(g *GomegaWithT, reqs []reconcile.Request) {
   274  				g.Expect(reqs).To(HaveLen(1))
   275  				g.Expect(reqs[0]).To(Equal(reconcile.Request{
   276  					NamespacedName: types.NamespacedName{
   277  						Name:      "azurepool2",
   278  						Namespace: "default",
   279  					},
   280  				}))
   281  			},
   282  		},
   283  	}
   284  
   285  	for _, c := range cases {
   286  		c := c
   287  		t.Run(c.Name, func(t *testing.T) {
   288  			t.Parallel()
   289  			g := NewGomegaWithT(t)
   290  			sink, mockctrl, fakeClient := c.Setup(t, g)
   291  			defer mockctrl.Finish()
   292  
   293  			f := AzureClusterToAzureMachinePoolsFunc(context.Background(), fakeClient, logr.New(sink))
   294  			reqs := f(context.TODO(), c.MapObjectFactory(g))
   295  			c.Expect(g, reqs)
   296  		})
   297  	}
   298  }