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 }