sigs.k8s.io/cluster-api@v1.7.1/controllers/external/util_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 external
    18  
    19  import (
    20  	"testing"
    21  
    22  	. "github.com/onsi/gomega"
    23  	"github.com/pkg/errors"
    24  	corev1 "k8s.io/api/core/v1"
    25  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    28  	ctrl "sigs.k8s.io/controller-runtime"
    29  	"sigs.k8s.io/controller-runtime/pkg/client"
    30  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    31  
    32  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    33  )
    34  
    35  var (
    36  	ctx = ctrl.SetupSignalHandler()
    37  )
    38  
    39  const (
    40  	testClusterName = "test-cluster"
    41  )
    42  
    43  func TestGetResourceFound(t *testing.T) {
    44  	g := NewWithT(t)
    45  
    46  	testResourceName := "greenTemplate"
    47  	testResourceKind := "GreenTemplate"
    48  	testResourceAPIVersion := "green.io/v1"
    49  	testResourceVersion := "999"
    50  
    51  	testResource := &unstructured.Unstructured{}
    52  	testResource.SetKind(testResourceKind)
    53  	testResource.SetAPIVersion(testResourceAPIVersion)
    54  	testResource.SetName(testResourceName)
    55  	testResource.SetNamespace(metav1.NamespaceDefault)
    56  	testResource.SetResourceVersion(testResourceVersion)
    57  
    58  	testResourceReference := &corev1.ObjectReference{
    59  		Kind:       testResourceKind,
    60  		APIVersion: testResourceAPIVersion,
    61  		Name:       testResourceName,
    62  		Namespace:  metav1.NamespaceDefault,
    63  	}
    64  
    65  	fakeClient := fake.NewClientBuilder().WithObjects(testResource.DeepCopy()).Build()
    66  	got, err := Get(ctx, fakeClient, testResourceReference, metav1.NamespaceDefault)
    67  	g.Expect(err).ToNot(HaveOccurred())
    68  	g.Expect(got).To(BeComparableTo(testResource))
    69  }
    70  
    71  func TestGetResourceNotFound(t *testing.T) {
    72  	g := NewWithT(t)
    73  
    74  	testResourceReference := &corev1.ObjectReference{
    75  		Kind:       "BlueTemplate",
    76  		APIVersion: "blue.io/v1",
    77  		Name:       "blueTemplate",
    78  		Namespace:  metav1.NamespaceDefault,
    79  	}
    80  
    81  	fakeClient := fake.NewClientBuilder().Build()
    82  	_, err := Get(ctx, fakeClient, testResourceReference, metav1.NamespaceDefault)
    83  	g.Expect(err).To(HaveOccurred())
    84  	g.Expect(apierrors.IsNotFound(errors.Cause(err))).To(BeTrue())
    85  }
    86  
    87  func TestCloneTemplateResourceNotFound(t *testing.T) {
    88  	g := NewWithT(t)
    89  
    90  	testClusterName := "bar"
    91  
    92  	testResourceReference := &corev1.ObjectReference{
    93  		Kind:       "OrangeTemplate",
    94  		APIVersion: "orange.io/v1",
    95  		Name:       "orangeTemplate",
    96  		Namespace:  metav1.NamespaceDefault,
    97  	}
    98  
    99  	fakeClient := fake.NewClientBuilder().Build()
   100  	_, err := CreateFromTemplate(ctx, &CreateFromTemplateInput{
   101  		Client:      fakeClient,
   102  		TemplateRef: testResourceReference,
   103  		Namespace:   metav1.NamespaceDefault,
   104  		ClusterName: testClusterName,
   105  	})
   106  	g.Expect(err).To(HaveOccurred())
   107  	g.Expect(apierrors.IsNotFound(errors.Cause(err))).To(BeTrue())
   108  }
   109  
   110  func TestCloneTemplateResourceFound(t *testing.T) {
   111  	g := NewWithT(t)
   112  
   113  	templateName := "purpleTemplate"
   114  	templateKind := "PurpleTemplate"
   115  	templateAPIVersion := "purple.io/v1"
   116  
   117  	template := unstructured.Unstructured{
   118  		Object: map[string]interface{}{
   119  			"kind":       templateKind,
   120  			"apiVersion": templateAPIVersion,
   121  			"metadata": map[string]interface{}{
   122  				"name":      templateName,
   123  				"namespace": metav1.NamespaceDefault,
   124  			},
   125  			"spec": map[string]interface{}{
   126  				"template": map[string]interface{}{
   127  					"metadata": map[string]interface{}{
   128  						"annotations": map[string]interface{}{
   129  							"test-template": "annotations",
   130  							"precedence":    "template",
   131  						},
   132  						"labels": map[string]interface{}{
   133  							"test-template": "label",
   134  							"precedence":    "template",
   135  						},
   136  					},
   137  					"spec": map[string]interface{}{
   138  						"hello": "world",
   139  					},
   140  				},
   141  			},
   142  		},
   143  	}
   144  
   145  	templateRef := corev1.ObjectReference{
   146  		Kind:       templateKind,
   147  		APIVersion: templateAPIVersion,
   148  		Name:       templateName,
   149  		Namespace:  metav1.NamespaceDefault,
   150  	}
   151  
   152  	owner := metav1.OwnerReference{
   153  		Kind:       "Cluster",
   154  		APIVersion: clusterv1.GroupVersion.String(),
   155  		Name:       testClusterName,
   156  	}
   157  
   158  	expectedKind := "Purple"
   159  	expectedAPIVersion := templateAPIVersion
   160  	expectedMetadata, ok, err := unstructured.NestedMap(template.UnstructuredContent(), "spec", "template", "metadata")
   161  	g.Expect(err).ToNot(HaveOccurred())
   162  	g.Expect(ok).To(BeTrue())
   163  	g.Expect(expectedMetadata).NotTo(BeEmpty())
   164  
   165  	expectedSpec, ok, err := unstructured.NestedMap(template.UnstructuredContent(), "spec", "template", "spec")
   166  	g.Expect(err).ToNot(HaveOccurred())
   167  	g.Expect(ok).To(BeTrue())
   168  	g.Expect(expectedSpec).NotTo(BeEmpty())
   169  
   170  	fakeClient := fake.NewClientBuilder().WithObjects(template.DeepCopy()).Build()
   171  
   172  	ref, err := CreateFromTemplate(ctx, &CreateFromTemplateInput{
   173  		Client:      fakeClient,
   174  		TemplateRef: templateRef.DeepCopy(),
   175  		Namespace:   metav1.NamespaceDefault,
   176  		ClusterName: testClusterName,
   177  		OwnerRef:    owner.DeepCopy(),
   178  		Labels: map[string]string{
   179  			"precedence":               "input",
   180  			clusterv1.ClusterNameLabel: "should-be-overwritten",
   181  		},
   182  		Annotations: map[string]string{
   183  			"precedence": "input",
   184  			clusterv1.TemplateClonedFromNameAnnotation: "should-be-overwritten",
   185  		},
   186  	})
   187  	g.Expect(err).ToNot(HaveOccurred())
   188  	g.Expect(ref).NotTo(BeNil())
   189  	g.Expect(ref.Kind).To(Equal(expectedKind))
   190  	g.Expect(ref.APIVersion).To(Equal(expectedAPIVersion))
   191  	g.Expect(ref.Namespace).To(Equal(metav1.NamespaceDefault))
   192  	g.Expect(ref.Name).To(HavePrefix(templateRef.Name))
   193  
   194  	clone := &unstructured.Unstructured{}
   195  	clone.SetKind(expectedKind)
   196  	clone.SetAPIVersion(expectedAPIVersion)
   197  
   198  	key := client.ObjectKey{Name: ref.Name, Namespace: ref.Namespace}
   199  	g.Expect(fakeClient.Get(ctx, key, clone)).To(Succeed())
   200  	g.Expect(clone.GetOwnerReferences()).To(HaveLen(1))
   201  	g.Expect(clone.GetOwnerReferences()).To(ContainElement(owner))
   202  
   203  	cloneSpec, ok, err := unstructured.NestedMap(clone.UnstructuredContent(), "spec")
   204  	g.Expect(err).ToNot(HaveOccurred())
   205  	g.Expect(ok).To(BeTrue())
   206  	g.Expect(cloneSpec).To(BeComparableTo(expectedSpec))
   207  
   208  	cloneLabels := clone.GetLabels()
   209  	g.Expect(cloneLabels).To(HaveKeyWithValue(clusterv1.ClusterNameLabel, testClusterName))
   210  	g.Expect(cloneLabels).To(HaveKeyWithValue("test-template", "label"))
   211  	g.Expect(cloneLabels).To(HaveKeyWithValue("precedence", "input"))
   212  
   213  	cloneAnnotations := clone.GetAnnotations()
   214  	g.Expect(cloneAnnotations).To(HaveKeyWithValue("test-template", "annotations"))
   215  	g.Expect(cloneAnnotations).To(HaveKeyWithValue("precedence", "input"))
   216  
   217  	g.Expect(cloneAnnotations).To(HaveKeyWithValue(clusterv1.TemplateClonedFromNameAnnotation, templateRef.Name))
   218  	g.Expect(cloneAnnotations).To(HaveKeyWithValue(clusterv1.TemplateClonedFromGroupKindAnnotation, templateRef.GroupVersionKind().GroupKind().String()))
   219  }
   220  
   221  func TestCloneTemplateResourceFoundNoOwner(t *testing.T) {
   222  	g := NewWithT(t)
   223  
   224  	templateName := "yellowTemplate"
   225  	templateKind := "YellowTemplate"
   226  	templateAPIVersion := "yellow.io/v1"
   227  
   228  	template := &unstructured.Unstructured{
   229  		Object: map[string]interface{}{
   230  			"kind":       templateKind,
   231  			"apiVersion": templateAPIVersion,
   232  			"metadata": map[string]interface{}{
   233  				"name":      templateName,
   234  				"namespace": metav1.NamespaceDefault,
   235  			},
   236  			"spec": map[string]interface{}{
   237  				"template": map[string]interface{}{
   238  					"spec": map[string]interface{}{
   239  						"hello": "world",
   240  					},
   241  				},
   242  			},
   243  		},
   244  	}
   245  
   246  	templateRef := &corev1.ObjectReference{
   247  		Kind:       templateKind,
   248  		APIVersion: templateAPIVersion,
   249  		Name:       templateName,
   250  		Namespace:  metav1.NamespaceDefault,
   251  	}
   252  
   253  	expectedKind := "Yellow"
   254  	expectedAPIVersion := templateAPIVersion
   255  	expectedLabels := map[string]string{clusterv1.ClusterNameLabel: testClusterName}
   256  
   257  	expectedSpec, ok, err := unstructured.NestedMap(template.UnstructuredContent(), "spec", "template", "spec")
   258  	g.Expect(err).ToNot(HaveOccurred())
   259  	g.Expect(ok).To(BeTrue())
   260  	g.Expect(expectedSpec).NotTo(BeEmpty())
   261  
   262  	fakeClient := fake.NewClientBuilder().WithObjects(template.DeepCopy()).Build()
   263  
   264  	ref, err := CreateFromTemplate(ctx, &CreateFromTemplateInput{
   265  		Client:      fakeClient,
   266  		TemplateRef: templateRef,
   267  		Namespace:   metav1.NamespaceDefault,
   268  		Name:        "object-name",
   269  		ClusterName: testClusterName,
   270  	})
   271  	g.Expect(err).ToNot(HaveOccurred())
   272  	g.Expect(ref).NotTo(BeNil())
   273  	g.Expect(ref.Kind).To(Equal(expectedKind))
   274  	g.Expect(ref.APIVersion).To(Equal(expectedAPIVersion))
   275  	g.Expect(ref.Namespace).To(Equal(metav1.NamespaceDefault))
   276  	g.Expect(ref.Name).To(Equal("object-name"))
   277  
   278  	clone := &unstructured.Unstructured{}
   279  	clone.SetKind(expectedKind)
   280  	clone.SetAPIVersion(expectedAPIVersion)
   281  	key := client.ObjectKey{Name: ref.Name, Namespace: ref.Namespace}
   282  	g.Expect(fakeClient.Get(ctx, key, clone)).To(Succeed())
   283  	g.Expect(clone.GetLabels()).To(Equal(expectedLabels))
   284  	g.Expect(clone.GetOwnerReferences()).To(BeEmpty())
   285  	cloneSpec, ok, err := unstructured.NestedMap(clone.UnstructuredContent(), "spec")
   286  	g.Expect(err).ToNot(HaveOccurred())
   287  	g.Expect(ok).To(BeTrue())
   288  	g.Expect(cloneSpec).To(BeComparableTo(expectedSpec))
   289  }
   290  
   291  func TestCloneTemplateMissingSpecTemplate(t *testing.T) {
   292  	g := NewWithT(t)
   293  
   294  	templateName := "aquaTemplate"
   295  	templateKind := "AquaTemplate"
   296  	templateAPIVersion := "aqua.io/v1"
   297  
   298  	template := &unstructured.Unstructured{
   299  		Object: map[string]interface{}{
   300  			"kind":       templateKind,
   301  			"apiVersion": templateAPIVersion,
   302  			"metadata": map[string]interface{}{
   303  				"name":      templateName,
   304  				"namespace": metav1.NamespaceDefault,
   305  			},
   306  			"spec": map[string]interface{}{},
   307  		},
   308  	}
   309  
   310  	templateRef := &corev1.ObjectReference{
   311  		Kind:       templateKind,
   312  		APIVersion: templateAPIVersion,
   313  		Name:       templateName,
   314  		Namespace:  metav1.NamespaceDefault,
   315  	}
   316  
   317  	fakeClient := fake.NewClientBuilder().WithObjects(template.DeepCopy()).Build()
   318  
   319  	_, err := CreateFromTemplate(ctx, &CreateFromTemplateInput{
   320  		Client:      fakeClient,
   321  		TemplateRef: templateRef,
   322  		Namespace:   metav1.NamespaceDefault,
   323  		ClusterName: testClusterName,
   324  	})
   325  	g.Expect(err).To(HaveOccurred())
   326  }