sigs.k8s.io/cluster-api@v1.6.3/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 ClusterName: testClusterName, 269 }) 270 g.Expect(err).ToNot(HaveOccurred()) 271 g.Expect(ref).NotTo(BeNil()) 272 g.Expect(ref.Kind).To(Equal(expectedKind)) 273 g.Expect(ref.APIVersion).To(Equal(expectedAPIVersion)) 274 g.Expect(ref.Namespace).To(Equal(metav1.NamespaceDefault)) 275 g.Expect(ref.Name).To(HavePrefix(templateRef.Name)) 276 277 clone := &unstructured.Unstructured{} 278 clone.SetKind(expectedKind) 279 clone.SetAPIVersion(expectedAPIVersion) 280 key := client.ObjectKey{Name: ref.Name, Namespace: ref.Namespace} 281 g.Expect(fakeClient.Get(ctx, key, clone)).To(Succeed()) 282 g.Expect(clone.GetLabels()).To(Equal(expectedLabels)) 283 g.Expect(clone.GetOwnerReferences()).To(BeEmpty()) 284 cloneSpec, ok, err := unstructured.NestedMap(clone.UnstructuredContent(), "spec") 285 g.Expect(err).ToNot(HaveOccurred()) 286 g.Expect(ok).To(BeTrue()) 287 g.Expect(cloneSpec).To(BeComparableTo(expectedSpec)) 288 } 289 290 func TestCloneTemplateMissingSpecTemplate(t *testing.T) { 291 g := NewWithT(t) 292 293 templateName := "aquaTemplate" 294 templateKind := "AquaTemplate" 295 templateAPIVersion := "aqua.io/v1" 296 297 template := &unstructured.Unstructured{ 298 Object: map[string]interface{}{ 299 "kind": templateKind, 300 "apiVersion": templateAPIVersion, 301 "metadata": map[string]interface{}{ 302 "name": templateName, 303 "namespace": metav1.NamespaceDefault, 304 }, 305 "spec": map[string]interface{}{}, 306 }, 307 } 308 309 templateRef := &corev1.ObjectReference{ 310 Kind: templateKind, 311 APIVersion: templateAPIVersion, 312 Name: templateName, 313 Namespace: metav1.NamespaceDefault, 314 } 315 316 fakeClient := fake.NewClientBuilder().WithObjects(template.DeepCopy()).Build() 317 318 _, err := CreateFromTemplate(ctx, &CreateFromTemplateInput{ 319 Client: fakeClient, 320 TemplateRef: templateRef, 321 Namespace: metav1.NamespaceDefault, 322 ClusterName: testClusterName, 323 }) 324 g.Expect(err).To(HaveOccurred()) 325 }