sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/client/cluster/cert_manager_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 cluster
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"testing"
    23  	"time"
    24  
    25  	. "github.com/onsi/gomega"
    26  	admissionregistration "k8s.io/api/admissionregistration/v1"
    27  	appsv1 "k8s.io/api/apps/v1"
    28  	corev1 "k8s.io/api/core/v1"
    29  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    30  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    31  	"k8s.io/apimachinery/pkg/api/meta"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    34  	"k8s.io/apimachinery/pkg/util/wait"
    35  	"sigs.k8s.io/controller-runtime/pkg/client"
    36  
    37  	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
    38  	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
    39  	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
    40  	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/scheme"
    41  	"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test"
    42  	utilyaml "sigs.k8s.io/cluster-api/util/yaml"
    43  )
    44  
    45  var certManagerDeploymentYaml = []byte("apiVersion: apps/v1\n" +
    46  	"kind: Deployment\n" +
    47  	"metadata:\n" +
    48  	"  name: cert-manager\n" +
    49  	"spec:\n" +
    50  	"  template:\n" +
    51  	"    spec:\n" +
    52  	"      containers:\n" +
    53  	"      - name: manager\n" +
    54  	"        image: quay.io/jetstack/cert-manager:v1.1.0\n")
    55  
    56  var certManagerNamespaceYaml = []byte("apiVersion: v1\n" +
    57  	"kind: Namespace\n" +
    58  	"metadata:\n" +
    59  	"  name: cert-manager\n")
    60  
    61  func Test_getManifestObjs(t *testing.T) {
    62  	g := NewWithT(t)
    63  
    64  	defaultConfigClient, err := config.New(context.Background(), "", config.InjectReader(test.NewFakeReader().WithImageMeta(config.CertManagerImageComponent, "bar-repository.io", "")))
    65  	g.Expect(err).ToNot(HaveOccurred())
    66  
    67  	type fields struct {
    68  		configClient config.Client
    69  		repository   repository.Repository
    70  	}
    71  	tests := []struct {
    72  		name    string
    73  		fields  fields
    74  		wantErr bool
    75  	}{
    76  		{
    77  			name: "successfully gets the cert-manager components",
    78  			fields: fields{
    79  				configClient: defaultConfigClient,
    80  				repository: repository.NewMemoryRepository().
    81  					WithPaths("root", "components.yaml").
    82  					WithDefaultVersion(config.CertManagerDefaultVersion).
    83  					WithFile(config.CertManagerDefaultVersion, "components.yaml", utilyaml.JoinYaml(certManagerNamespaceYaml, certManagerDeploymentYaml)),
    84  			},
    85  			wantErr: false,
    86  		},
    87  		{
    88  			name: "fails if the file does not exists",
    89  			fields: fields{
    90  				configClient: defaultConfigClient,
    91  				repository: repository.NewMemoryRepository().
    92  					WithPaths("root", "components.yaml").
    93  					WithDefaultVersion("v1.0.0"),
    94  			},
    95  			wantErr: true,
    96  		},
    97  		{
    98  			name: "fails if the file does not exists for the desired version",
    99  			fields: fields{
   100  				configClient: defaultConfigClient,
   101  				repository: repository.NewMemoryRepository().
   102  					WithPaths("root", "components.yaml").
   103  					WithDefaultVersion("v99.0.0").
   104  					WithFile("v99.0.0", "components.yaml", utilyaml.JoinYaml(certManagerNamespaceYaml, certManagerDeploymentYaml)),
   105  			},
   106  			wantErr: true,
   107  		},
   108  		{
   109  			name: "successfully gets the cert-manager components for a custom release",
   110  			fields: fields{
   111  				configClient: func() config.Client {
   112  					configClient, err := config.New(context.Background(), "", config.InjectReader(test.NewFakeReader().WithImageMeta(config.CertManagerImageComponent, "bar-repository.io", "").WithCertManager("", "v1.0.0", "")))
   113  					g.Expect(err).ToNot(HaveOccurred())
   114  					return configClient
   115  				}(),
   116  				repository: repository.NewMemoryRepository().
   117  					WithPaths("root", "components.yaml").
   118  					WithDefaultVersion(config.CertManagerDefaultVersion).
   119  					WithFile(config.CertManagerDefaultVersion, "components.yaml", utilyaml.JoinYaml(certManagerNamespaceYaml, certManagerDeploymentYaml)),
   120  			},
   121  			wantErr: false,
   122  		},
   123  	}
   124  	for _, tt := range tests {
   125  		t.Run(tt.name, func(t *testing.T) {
   126  			g := NewWithT(t)
   127  
   128  			ctx := context.Background()
   129  
   130  			cm := &certManagerClient{
   131  				configClient: defaultConfigClient,
   132  				repositoryClientFactory: func(ctx context.Context, provider config.Provider, configClient config.Client, _ ...repository.Option) (repository.Client, error) {
   133  					return repository.New(ctx, provider, configClient, repository.InjectRepository(tt.fields.repository))
   134  				},
   135  			}
   136  
   137  			certManagerConfig, err := cm.configClient.CertManager().Get()
   138  			g.Expect(err).ToNot(HaveOccurred())
   139  
   140  			got, err := cm.getManifestObjs(ctx, certManagerConfig)
   141  			if tt.wantErr {
   142  				g.Expect(err).To(HaveOccurred())
   143  				return
   144  			}
   145  			g.Expect(err).ToNot(HaveOccurred())
   146  
   147  			for i := range got {
   148  				o := &got[i]
   149  				// Assert Get adds clusterctl labels.
   150  				g.Expect(o.GetLabels()).To(HaveKey(clusterctlv1.ClusterctlLabel))
   151  				g.Expect(o.GetLabels()).To(HaveKey(clusterctlv1.ClusterctlCoreLabel))
   152  				g.Expect(o.GetLabels()[clusterctlv1.ClusterctlCoreLabel]).To(Equal(clusterctlv1.ClusterctlCoreLabelCertManagerValue))
   153  
   154  				// Assert Get adds clusterctl annotations.
   155  				g.Expect(o.GetAnnotations()).To(HaveKey(clusterctlv1.CertManagerVersionAnnotation))
   156  				g.Expect(o.GetAnnotations()[clusterctlv1.CertManagerVersionAnnotation]).To(Equal(certManagerConfig.Version()))
   157  
   158  				// Assert Get fixes images.
   159  				if o.GetKind() == "Deployment" {
   160  					// Convert Unstructured into a typed object
   161  					d := &appsv1.Deployment{}
   162  					g.Expect(scheme.Scheme.Convert(o, d, nil)).To(Succeed())
   163  					g.Expect(d.Spec.Template.Spec.Containers[0].Image).To(Equal("bar-repository.io/cert-manager:v1.1.0"))
   164  				}
   165  			}
   166  		})
   167  	}
   168  }
   169  
   170  func Test_GetTimeout(t *testing.T) {
   171  	pollImmediateWaiter := func(context.Context, time.Duration, time.Duration, wait.ConditionWithContextFunc) error {
   172  		return nil
   173  	}
   174  
   175  	tests := []struct {
   176  		name   string
   177  		config *fakeConfigClient
   178  		want   time.Duration
   179  	}{
   180  		{
   181  			name:   "no custom value set for timeout",
   182  			config: newFakeConfig(),
   183  			want:   10 * time.Minute,
   184  		},
   185  		{
   186  			name:   "a custom value of timeout is set",
   187  			config: newFakeConfig().WithCertManager("", "", "5m"),
   188  			want:   5 * time.Minute,
   189  		},
   190  		{
   191  			name:   "invalid custom value of timeout is set",
   192  			config: newFakeConfig().WithCertManager("", "", "foo"),
   193  			want:   10 * time.Minute,
   194  		},
   195  	}
   196  	for _, tt := range tests {
   197  		t.Run(tt.name, func(t *testing.T) {
   198  			g := NewWithT(t)
   199  
   200  			cm := newCertManagerClient(tt.config, nil, nil, pollImmediateWaiter)
   201  
   202  			tm := cm.getWaitTimeout()
   203  
   204  			g.Expect(tm).To(Equal(tt.want))
   205  		})
   206  	}
   207  }
   208  
   209  func Test_shouldUpgrade(t *testing.T) {
   210  	type args struct {
   211  		objs []unstructured.Unstructured
   212  	}
   213  	tests := []struct {
   214  		name            string
   215  		configVersion   string
   216  		args            args
   217  		wantFromVersion string
   218  		wantToVersion   string
   219  		want            bool
   220  		wantErr         bool
   221  	}{
   222  		{
   223  			name: "Version is not defined (e.g. cluster created with clusterctl < v0.3.9), should upgrade",
   224  			args: args{
   225  				objs: []unstructured.Unstructured{
   226  					{
   227  						Object: map[string]interface{}{},
   228  					},
   229  				},
   230  			},
   231  			wantFromVersion: "v0.11.0",
   232  			wantToVersion:   config.CertManagerDefaultVersion,
   233  			want:            true,
   234  			wantErr:         false,
   235  		},
   236  		{
   237  			name: "Version is equal, should not upgrade",
   238  			args: args{
   239  				objs: []unstructured.Unstructured{
   240  					{
   241  						Object: map[string]interface{}{
   242  							"metadata": map[string]interface{}{
   243  								"annotations": map[string]interface{}{
   244  									clusterctlv1.CertManagerVersionAnnotation: config.CertManagerDefaultVersion,
   245  								},
   246  							},
   247  						},
   248  					},
   249  				},
   250  			},
   251  			wantFromVersion: config.CertManagerDefaultVersion,
   252  			wantToVersion:   config.CertManagerDefaultVersion,
   253  			want:            false,
   254  			wantErr:         false,
   255  		},
   256  		{
   257  			name:          "Version is equal but current version has no build metadata, should upgrade",
   258  			configVersion: "v1.5.3+h4fd4",
   259  			args: args{
   260  				objs: []unstructured.Unstructured{
   261  					{
   262  						Object: map[string]interface{}{
   263  							"metadata": map[string]interface{}{
   264  								"annotations": map[string]interface{}{
   265  									clusterctlv1.CertManagerVersionAnnotation: "v1.5.3",
   266  								},
   267  							},
   268  						},
   269  					},
   270  				},
   271  			},
   272  			wantFromVersion: "v1.5.3",
   273  			wantToVersion:   "v1.5.3+h4fd4",
   274  			want:            true,
   275  			wantErr:         false,
   276  		},
   277  		{
   278  			name:          "Version is equal but different build metadata with hash, should upgrade",
   279  			configVersion: "v1.5.3+h4fd4",
   280  			args: args{
   281  				objs: []unstructured.Unstructured{
   282  					{
   283  						Object: map[string]interface{}{
   284  							"metadata": map[string]interface{}{
   285  								"annotations": map[string]interface{}{
   286  									clusterctlv1.CertManagerVersionAnnotation: "v1.5.3+h4fd5",
   287  								},
   288  							},
   289  						},
   290  					},
   291  				},
   292  			},
   293  			wantFromVersion: "v1.5.3+h4fd5",
   294  			wantToVersion:   "v1.5.3+h4fd4",
   295  			want:            true,
   296  			wantErr:         false,
   297  		},
   298  		{
   299  			name:          "Version is equal and same build metadata with hash, should not upgrade",
   300  			configVersion: "v1.5.3+h4fd5",
   301  			args: args{
   302  				objs: []unstructured.Unstructured{
   303  					{
   304  						Object: map[string]interface{}{
   305  							"metadata": map[string]interface{}{
   306  								"annotations": map[string]interface{}{
   307  									clusterctlv1.CertManagerVersionAnnotation: "v1.5.3+h4fd5",
   308  								},
   309  							},
   310  						},
   311  					},
   312  				},
   313  			},
   314  			wantFromVersion: "v1.5.3+h4fd5",
   315  			wantToVersion:   "v1.5.3+h4fd5",
   316  			want:            false,
   317  			wantErr:         false,
   318  		},
   319  		{
   320  			name:          "Version is equal but older numbered build metadata, should not upgrade",
   321  			configVersion: "v1.5.3+build.1",
   322  			args: args{
   323  				objs: []unstructured.Unstructured{
   324  					{
   325  						Object: map[string]interface{}{
   326  							"metadata": map[string]interface{}{
   327  								"annotations": map[string]interface{}{
   328  									clusterctlv1.CertManagerVersionAnnotation: "v1.5.3+build.2",
   329  								},
   330  							},
   331  						},
   332  					},
   333  				},
   334  			},
   335  			wantFromVersion: "v1.5.3+build.2",
   336  			wantToVersion:   "v1.5.3+build.1",
   337  			want:            false,
   338  			wantErr:         false,
   339  		},
   340  		{
   341  			name:          "Version is equal but newer numbered build metadata, should upgrade",
   342  			configVersion: "v1.5.3+build.3",
   343  			args: args{
   344  				objs: []unstructured.Unstructured{
   345  					{
   346  						Object: map[string]interface{}{
   347  							"metadata": map[string]interface{}{
   348  								"annotations": map[string]interface{}{
   349  									clusterctlv1.CertManagerVersionAnnotation: "v1.5.3+build.2",
   350  								},
   351  							},
   352  						},
   353  					},
   354  				},
   355  			},
   356  			wantFromVersion: "v1.5.3+build.2",
   357  			wantToVersion:   "v1.5.3+build.3",
   358  			want:            true,
   359  			wantErr:         false,
   360  		},
   361  		{
   362  			name: "Version is older, should upgrade",
   363  			args: args{
   364  				objs: []unstructured.Unstructured{
   365  					{
   366  						Object: map[string]interface{}{
   367  							"metadata": map[string]interface{}{
   368  								"annotations": map[string]interface{}{
   369  									clusterctlv1.CertManagerVersionAnnotation: "v0.11.0",
   370  								},
   371  							},
   372  						},
   373  					},
   374  				},
   375  			},
   376  			wantFromVersion: "v0.11.0",
   377  			wantToVersion:   config.CertManagerDefaultVersion,
   378  			want:            true,
   379  			wantErr:         false,
   380  		},
   381  		{
   382  			name: "Version is newer, should not upgrade",
   383  			args: args{
   384  				objs: []unstructured.Unstructured{
   385  					{
   386  						Object: map[string]interface{}{
   387  							"metadata": map[string]interface{}{
   388  								"annotations": map[string]interface{}{
   389  									clusterctlv1.CertManagerVersionAnnotation: "v100.0.0",
   390  								},
   391  							},
   392  						},
   393  					},
   394  				},
   395  			},
   396  			wantFromVersion: "v100.0.0",
   397  			wantToVersion:   config.CertManagerDefaultVersion,
   398  			want:            false,
   399  			wantErr:         false,
   400  		},
   401  		{
   402  			name: "Endpoint are ignored",
   403  			args: args{
   404  				objs: []unstructured.Unstructured{
   405  					{
   406  						Object: map[string]interface{}{
   407  							"kind": "Endpoints",
   408  							"metadata": map[string]interface{}{
   409  								"annotations": map[string]interface{}{
   410  									clusterctlv1.CertManagerVersionAnnotation: config.CertManagerDefaultVersion,
   411  								},
   412  							},
   413  						},
   414  					},
   415  				},
   416  			},
   417  			wantFromVersion: "",
   418  			wantToVersion:   config.CertManagerDefaultVersion,
   419  			want:            false,
   420  			wantErr:         false,
   421  		},
   422  	}
   423  	for _, tt := range tests {
   424  		t.Run(tt.name, func(t *testing.T) {
   425  			g := NewWithT(t)
   426  
   427  			proxy := test.NewFakeProxy()
   428  			fakeConfigClient := newFakeConfig().WithCertManager("", tt.configVersion, "")
   429  			pollImmediateWaiter := func(context.Context, time.Duration, time.Duration, wait.ConditionWithContextFunc) error {
   430  				return nil
   431  			}
   432  			cm := newCertManagerClient(fakeConfigClient, nil, proxy, pollImmediateWaiter)
   433  
   434  			fromVersion, toVersion, got, err := cm.shouldUpgrade(tt.args.objs)
   435  			if tt.wantErr {
   436  				g.Expect(err).To(HaveOccurred())
   437  				return
   438  			}
   439  			g.Expect(err).ToNot(HaveOccurred())
   440  
   441  			g.Expect(got).To(Equal(tt.want))
   442  			g.Expect(fromVersion).To(Equal(tt.wantFromVersion))
   443  			g.Expect(toVersion).To(Equal(tt.wantToVersion))
   444  		})
   445  	}
   446  }
   447  
   448  func Test_certManagerClient_deleteObjs(t *testing.T) {
   449  	type fields struct {
   450  		objs []client.Object
   451  	}
   452  	tests := []struct {
   453  		name    string
   454  		fields  fields
   455  		want    []string // Define the list of "Kind, Namespace/Name" that should still exist after delete
   456  		wantErr bool
   457  	}{
   458  		{
   459  			name: "CRD should not be deleted",
   460  			fields: fields{
   461  				objs: []client.Object{
   462  					&apiextensionsv1.CustomResourceDefinition{
   463  						TypeMeta: metav1.TypeMeta{
   464  							Kind:       "CustomResourceDefinition",
   465  							APIVersion: apiextensionsv1.SchemeGroupVersion.String(),
   466  						},
   467  						ObjectMeta: metav1.ObjectMeta{
   468  							Name:   "foo",
   469  							Labels: map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   470  						},
   471  					},
   472  				},
   473  			},
   474  			want:    []string{"CustomResourceDefinition, /foo"},
   475  			wantErr: false,
   476  		},
   477  		{
   478  			name: "Namespace should not be deleted",
   479  			fields: fields{
   480  				objs: []client.Object{
   481  					&corev1.Namespace{
   482  						TypeMeta: metav1.TypeMeta{
   483  							Kind:       "Namespace",
   484  							APIVersion: corev1.SchemeGroupVersion.String(),
   485  						},
   486  						ObjectMeta: metav1.ObjectMeta{
   487  							Name:   "foo",
   488  							Labels: map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   489  						},
   490  					},
   491  				},
   492  			},
   493  			want:    []string{"Namespace, /foo"},
   494  			wantErr: false,
   495  		},
   496  		{
   497  			name: "MutatingWebhookConfiguration should not be deleted",
   498  			fields: fields{
   499  				objs: []client.Object{
   500  					&admissionregistration.MutatingWebhookConfiguration{
   501  						TypeMeta: metav1.TypeMeta{
   502  							Kind:       "MutatingWebhookConfiguration",
   503  							APIVersion: admissionregistration.SchemeGroupVersion.String(),
   504  						},
   505  						ObjectMeta: metav1.ObjectMeta{
   506  							Name:   "foo",
   507  							Labels: map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   508  						},
   509  					},
   510  				},
   511  			},
   512  			want:    []string{"MutatingWebhookConfiguration, /foo"},
   513  			wantErr: false,
   514  		},
   515  		{
   516  			name: "ValidatingWebhookConfiguration should not be deleted",
   517  			fields: fields{
   518  				objs: []client.Object{
   519  					&admissionregistration.ValidatingWebhookConfiguration{
   520  						TypeMeta: metav1.TypeMeta{
   521  							Kind:       "ValidatingWebhookConfiguration",
   522  							APIVersion: admissionregistration.SchemeGroupVersion.String(),
   523  						},
   524  						ObjectMeta: metav1.ObjectMeta{
   525  							Name:   "foo",
   526  							Labels: map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   527  						},
   528  					},
   529  				},
   530  			},
   531  			want:    []string{"ValidatingWebhookConfiguration, /foo"},
   532  			wantErr: false,
   533  		},
   534  		{
   535  			name: "Other resources should be deleted",
   536  			fields: fields{
   537  				objs: []client.Object{
   538  					&corev1.ServiceAccount{
   539  						TypeMeta: metav1.TypeMeta{
   540  							Kind:       "ServiceAccount",
   541  							APIVersion: corev1.SchemeGroupVersion.String(),
   542  						},
   543  						ObjectMeta: metav1.ObjectMeta{
   544  							Name:   "foo",
   545  							Labels: map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   546  						},
   547  					},
   548  					&appsv1.Deployment{
   549  						TypeMeta: metav1.TypeMeta{
   550  							Kind:       "Deployment",
   551  							APIVersion: appsv1.SchemeGroupVersion.String(),
   552  						},
   553  						ObjectMeta: metav1.ObjectMeta{
   554  							Name:   "bar",
   555  							Labels: map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   556  						},
   557  					},
   558  				},
   559  			},
   560  			want:    nil,
   561  			wantErr: false,
   562  		},
   563  	}
   564  	for _, tt := range tests {
   565  		t.Run(tt.name, func(t *testing.T) {
   566  			g := NewWithT(t)
   567  
   568  			ctx := context.Background()
   569  
   570  			proxy := test.NewFakeProxy().WithObjs(tt.fields.objs...)
   571  			cm := &certManagerClient{
   572  				pollImmediateWaiter: fakePollImmediateWaiter,
   573  				proxy:               proxy,
   574  			}
   575  
   576  			objBefore, err := proxy.ListResources(ctx, map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue})
   577  			g.Expect(err).ToNot(HaveOccurred())
   578  
   579  			err = cm.deleteObjs(ctx, objBefore)
   580  			if tt.wantErr {
   581  				g.Expect(err).To(HaveOccurred())
   582  				return
   583  			}
   584  			g.Expect(err).ToNot(HaveOccurred())
   585  
   586  			for _, obj := range tt.fields.objs {
   587  				accessor, err := meta.Accessor(obj)
   588  				g.Expect(err).ToNot(HaveOccurred())
   589  
   590  				objShouldStillExist := false
   591  				for _, want := range tt.want {
   592  					if fmt.Sprintf("%s, %s/%s", obj.GetObjectKind().GroupVersionKind().Kind, accessor.GetNamespace(), accessor.GetName()) == want {
   593  						objShouldStillExist = true
   594  					}
   595  				}
   596  
   597  				cl, err := proxy.NewClient(ctx)
   598  				g.Expect(err).ToNot(HaveOccurred())
   599  
   600  				err = cl.Get(context.Background(), client.ObjectKeyFromObject(obj), obj)
   601  				switch objShouldStillExist {
   602  				case true:
   603  					g.Expect(err).ToNot(HaveOccurred())
   604  				case false:
   605  					g.Expect(apierrors.IsNotFound(err)).To(BeTrue())
   606  				}
   607  			}
   608  		})
   609  	}
   610  }
   611  
   612  func Test_certManagerClient_PlanUpgrade(t *testing.T) {
   613  	tests := []struct {
   614  		name         string
   615  		objs         []client.Object
   616  		expectErr    bool
   617  		expectedPlan CertManagerUpgradePlan
   618  	}{
   619  		{
   620  			name: "returns the upgrade plan for cert-manager if v0.11.0 is installed",
   621  			// Cert-manager deployment without annotation, this must be from
   622  			// v0.11.0
   623  			objs: []client.Object{
   624  				&appsv1.Deployment{
   625  					TypeMeta: metav1.TypeMeta{
   626  						Kind:       "Deployment",
   627  						APIVersion: appsv1.SchemeGroupVersion.String(),
   628  					},
   629  					ObjectMeta: metav1.ObjectMeta{
   630  						Name:   "cert-manager",
   631  						Labels: map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   632  					},
   633  				},
   634  			},
   635  			expectErr: false,
   636  			expectedPlan: CertManagerUpgradePlan{
   637  				From:          "v0.11.0",
   638  				To:            config.CertManagerDefaultVersion,
   639  				ShouldUpgrade: true,
   640  			},
   641  		},
   642  		{
   643  			name: "returns the upgrade plan for cert-manager if an older version is installed",
   644  			objs: []client.Object{
   645  				&appsv1.Deployment{
   646  					TypeMeta: metav1.TypeMeta{
   647  						Kind:       "Deployment",
   648  						APIVersion: appsv1.SchemeGroupVersion.String(),
   649  					},
   650  					ObjectMeta: metav1.ObjectMeta{
   651  						Name:        "cert-manager",
   652  						Labels:      map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   653  						Annotations: map[string]string{clusterctlv1.CertManagerVersionAnnotation: "v0.10.2"},
   654  					},
   655  				},
   656  			},
   657  			expectErr: false,
   658  			expectedPlan: CertManagerUpgradePlan{
   659  				From:          "v0.10.2",
   660  				To:            config.CertManagerDefaultVersion,
   661  				ShouldUpgrade: true,
   662  			},
   663  		},
   664  		{
   665  			name: "returns plan if shouldn't upgrade",
   666  			objs: []client.Object{
   667  				&appsv1.Deployment{
   668  					TypeMeta: metav1.TypeMeta{
   669  						Kind:       "Deployment",
   670  						APIVersion: appsv1.SchemeGroupVersion.String(),
   671  					},
   672  					ObjectMeta: metav1.ObjectMeta{
   673  						Name:        "cert-manager",
   674  						Labels:      map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   675  						Annotations: map[string]string{clusterctlv1.CertManagerVersionAnnotation: config.CertManagerDefaultVersion},
   676  					},
   677  				},
   678  			},
   679  			expectErr: false,
   680  			expectedPlan: CertManagerUpgradePlan{
   681  				From:          config.CertManagerDefaultVersion,
   682  				To:            config.CertManagerDefaultVersion,
   683  				ShouldUpgrade: false,
   684  			},
   685  		},
   686  		{
   687  			name: "returns empty plan and error if cannot parse semver",
   688  			objs: []client.Object{
   689  				&appsv1.Deployment{
   690  					TypeMeta: metav1.TypeMeta{
   691  						Kind:       "Deployment",
   692  						APIVersion: appsv1.SchemeGroupVersion.String(),
   693  					},
   694  					ObjectMeta: metav1.ObjectMeta{
   695  						Name:        "cert-manager",
   696  						Labels:      map[string]string{clusterctlv1.ClusterctlCoreLabel: clusterctlv1.ClusterctlCoreLabelCertManagerValue},
   697  						Annotations: map[string]string{clusterctlv1.CertManagerVersionAnnotation: "bad-sem-ver"},
   698  					},
   699  				},
   700  			},
   701  			expectErr: true,
   702  			expectedPlan: CertManagerUpgradePlan{
   703  				From:          "",
   704  				To:            "",
   705  				ShouldUpgrade: false,
   706  			},
   707  		},
   708  	}
   709  
   710  	for _, tt := range tests {
   711  		t.Run(tt.name, func(t *testing.T) {
   712  			g := NewWithT(t)
   713  
   714  			ctx := context.Background()
   715  
   716  			proxy := test.NewFakeProxy().WithObjs(tt.objs...)
   717  			fakeConfigClient := newFakeConfig()
   718  			pollImmediateWaiter := func(context.Context, time.Duration, time.Duration, wait.ConditionWithContextFunc) error {
   719  				return nil
   720  			}
   721  			cm := newCertManagerClient(fakeConfigClient, nil, proxy, pollImmediateWaiter)
   722  
   723  			actualPlan, err := cm.PlanUpgrade(ctx)
   724  			if tt.expectErr {
   725  				g.Expect(err).To(HaveOccurred())
   726  				g.Expect(actualPlan).To(BeComparableTo(CertManagerUpgradePlan{}))
   727  				return
   728  			}
   729  			g.Expect(err).ToNot(HaveOccurred())
   730  			g.Expect(actualPlan).To(Equal(tt.expectedPlan))
   731  		})
   732  	}
   733  }
   734  
   735  func Test_certManagerClient_EnsureLatestVersion(t *testing.T) {
   736  	type fields struct {
   737  		proxy Proxy
   738  	}
   739  	tests := []struct {
   740  		name    string
   741  		fields  fields
   742  		wantErr bool
   743  	}{
   744  		{
   745  			name: "",
   746  			fields: fields{
   747  				proxy: test.NewFakeProxy().WithObjs(
   748  					&corev1.Namespace{
   749  						ObjectMeta: metav1.ObjectMeta{
   750  							Labels: map[string]string{},
   751  						},
   752  					},
   753  				),
   754  			},
   755  			wantErr: false,
   756  		},
   757  	}
   758  	for _, tt := range tests {
   759  		t.Run(tt.name, func(t *testing.T) {
   760  			g := NewWithT(t)
   761  
   762  			cm := &certManagerClient{
   763  				proxy: tt.fields.proxy,
   764  			}
   765  
   766  			err := cm.EnsureLatestVersion(context.Background())
   767  			if tt.wantErr {
   768  				g.Expect(err).To(HaveOccurred())
   769  				return
   770  			}
   771  			g.Expect(err).ToNot(HaveOccurred())
   772  		})
   773  	}
   774  }
   775  
   776  func newFakeConfig() *fakeConfigClient {
   777  	fakeReader := test.NewFakeReader()
   778  
   779  	client, _ := config.New(context.Background(), "fake-config", config.InjectReader(fakeReader))
   780  	return &fakeConfigClient{
   781  		fakeReader:     fakeReader,
   782  		internalclient: client,
   783  	}
   784  }
   785  
   786  type fakeConfigClient struct {
   787  	fakeReader     *test.FakeReader
   788  	internalclient config.Client
   789  }
   790  
   791  var _ config.Client = &fakeConfigClient{}
   792  
   793  func (f fakeConfigClient) CertManager() config.CertManagerClient {
   794  	return f.internalclient.CertManager()
   795  }
   796  
   797  func (f fakeConfigClient) Providers() config.ProvidersClient {
   798  	return f.internalclient.Providers()
   799  }
   800  
   801  func (f fakeConfigClient) Variables() config.VariablesClient {
   802  	return f.internalclient.Variables()
   803  }
   804  
   805  func (f fakeConfigClient) ImageMeta() config.ImageMetaClient {
   806  	return f.internalclient.ImageMeta()
   807  }
   808  
   809  func (f *fakeConfigClient) WithVar(key, value string) *fakeConfigClient {
   810  	f.fakeReader.WithVar(key, value)
   811  	return f
   812  }
   813  
   814  func (f *fakeConfigClient) WithProvider(provider config.Provider) *fakeConfigClient {
   815  	f.fakeReader.WithProvider(provider.Name(), provider.Type(), provider.URL())
   816  	return f
   817  }
   818  
   819  func (f *fakeConfigClient) WithCertManager(url, version, timeout string) *fakeConfigClient {
   820  	f.fakeReader.WithCertManager(url, version, timeout)
   821  	return f
   822  }