sigs.k8s.io/cluster-api@v1.7.1/util/log/log_test.go (about) 1 /* 2 Copyright 2022 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 log 18 19 import ( 20 "context" 21 "testing" 22 23 "github.com/go-logr/logr" 24 . "github.com/onsi/gomega" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/klog/v2" 29 ctrl "sigs.k8s.io/controller-runtime" 30 "sigs.k8s.io/controller-runtime/pkg/client" 31 "sigs.k8s.io/controller-runtime/pkg/client/fake" 32 "sigs.k8s.io/controller-runtime/pkg/log" 33 34 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 35 ) 36 37 func Test_AddObjectHierarchy(t *testing.T) { 38 g := NewWithT(t) 39 40 scheme := runtime.NewScheme() 41 g.Expect(clusterv1.AddToScheme(scheme)).To(Succeed()) 42 43 md := &clusterv1.MachineSet{ 44 TypeMeta: metav1.TypeMeta{ 45 APIVersion: clusterv1.GroupVersion.String(), 46 Kind: "MachineDeployment", 47 }, 48 ObjectMeta: metav1.ObjectMeta{ 49 Namespace: metav1.NamespaceDefault, 50 Name: "development-3961-md-0-l4zn6", 51 }, 52 } 53 mdOwnerRef := metav1.OwnerReference{ 54 APIVersion: md.APIVersion, 55 Kind: md.Kind, 56 Name: md.Name, 57 } 58 59 ms := &clusterv1.MachineSet{ 60 TypeMeta: metav1.TypeMeta{ 61 APIVersion: clusterv1.GroupVersion.String(), 62 Kind: "MachineSet", 63 }, 64 ObjectMeta: metav1.ObjectMeta{ 65 Namespace: metav1.NamespaceDefault, 66 Name: "development-3961-md-0-l4zn6-758c9b7677", 67 OwnerReferences: []metav1.OwnerReference{mdOwnerRef}, 68 }, 69 } 70 msOwnerRef := metav1.OwnerReference{ 71 APIVersion: ms.APIVersion, 72 Kind: ms.Kind, 73 Name: ms.Name, 74 } 75 76 tests := []struct { 77 name string 78 obj metav1.Object 79 objects []client.Object 80 expectedKeysAndValues []interface{} 81 }{ 82 { 83 name: "MachineSet owning Machine is added", 84 // MachineSet does not exist in Kubernetes so only MachineSet is added 85 // and MachineDeployment is not. 86 obj: &clusterv1.Machine{ 87 ObjectMeta: metav1.ObjectMeta{ 88 OwnerReferences: []metav1.OwnerReference{msOwnerRef}, 89 Namespace: metav1.NamespaceDefault, 90 }, 91 }, 92 expectedKeysAndValues: []interface{}{ 93 "MachineSet", 94 klog.ObjectRef{Namespace: ms.Namespace, Name: ms.Name}, 95 }, 96 }, 97 { 98 name: "MachineDeployment and MachineSet owning Machine is added", 99 obj: &clusterv1.Machine{ 100 ObjectMeta: metav1.ObjectMeta{ 101 OwnerReferences: []metav1.OwnerReference{msOwnerRef}, 102 Namespace: metav1.NamespaceDefault, 103 }, 104 }, 105 objects: []client.Object{ms}, 106 expectedKeysAndValues: []interface{}{ 107 "MachineSet", 108 klog.ObjectRef{Namespace: ms.Namespace, Name: ms.Name}, 109 "MachineDeployment", 110 klog.ObjectRef{Namespace: md.Namespace, Name: md.Name}, 111 }, 112 }, 113 { 114 name: "MachineDeployment owning MachineSet is added", 115 obj: &clusterv1.MachineSet{ 116 ObjectMeta: metav1.ObjectMeta{ 117 OwnerReferences: []metav1.OwnerReference{mdOwnerRef}, 118 Namespace: metav1.NamespaceDefault, 119 }, 120 }, 121 expectedKeysAndValues: []interface{}{ 122 "MachineDeployment", 123 klog.ObjectRef{Namespace: md.Namespace, Name: md.Name}, 124 }, 125 }, 126 { 127 name: "KubeadmControlPlane and Machine owning DockerMachine are added", 128 obj: &unstructured.Unstructured{ 129 Object: map[string]interface{}{ 130 "apiVersion": "infrastructure.cluster.x-k8s.io/v1beta1", 131 "kind": "DockerMachine", 132 "metadata": map[string]interface{}{ 133 "ownerReferences": []interface{}{ 134 map[string]interface{}{ 135 "apiVersion": clusterv1.GroupVersion.String(), 136 "kind": "Machine", 137 "name": "development-3961-4flkb-gzxnb", 138 }, 139 map[string]interface{}{ 140 "apiVersion": clusterv1.GroupVersion.String(), 141 "kind": "KubeadmControlPlane", 142 "name": "development-3961-4flkb", 143 }, 144 }, 145 "namespace": metav1.NamespaceDefault, 146 }, 147 }, 148 }, 149 expectedKeysAndValues: []interface{}{ 150 "Machine", 151 klog.ObjectRef{Namespace: metav1.NamespaceDefault, Name: "development-3961-4flkb-gzxnb"}, 152 "KubeadmControlPlane", 153 klog.ObjectRef{Namespace: metav1.NamespaceDefault, Name: "development-3961-4flkb"}, 154 }, 155 }, 156 { 157 name: "Duplicate Cluster ownerRef should be deduplicated", 158 obj: &unstructured.Unstructured{ 159 Object: map[string]interface{}{ 160 "apiVersion": "infrastructure.cluster.x-k8s.io/v1beta1", 161 "kind": "DockerCluster", 162 "metadata": map[string]interface{}{ 163 "ownerReferences": []interface{}{ 164 map[string]interface{}{ 165 "apiVersion": clusterv1.GroupVersion.String(), 166 "kind": "Cluster", 167 "name": "development-3961", 168 }, 169 map[string]interface{}{ 170 "apiVersion": clusterv1.GroupVersion.String(), 171 "kind": "Cluster", 172 "name": "development-3961", 173 }, 174 }, 175 "namespace": metav1.NamespaceDefault, 176 }, 177 }, 178 }, 179 expectedKeysAndValues: []interface{}{ 180 "Cluster", 181 klog.ObjectRef{Namespace: metav1.NamespaceDefault, Name: "development-3961"}, 182 }, 183 }, 184 } 185 for _, tt := range tests { 186 t.Run(tt.name, func(t *testing.T) { 187 g := NewWithT(t) 188 189 c := fake.NewClientBuilder(). 190 WithScheme(scheme). 191 WithObjects(tt.objects...). 192 Build() 193 194 // Create fake log sink so we can later verify the added k/v pairs. 195 ctx := ctrl.LoggerInto(context.Background(), logr.New(&fakeLogSink{})) 196 197 _, logger, err := AddOwners(ctx, c, tt.obj) 198 g.Expect(err).ToNot(HaveOccurred()) 199 g.Expect(logger.GetSink().(fakeLogSink).keysAndValues).To(Equal(tt.expectedKeysAndValues)) 200 }) 201 } 202 } 203 204 type fakeLogSink struct { 205 // Embedding NullLogSink so we don't have to implement all funcs 206 // of the LogSink interface. 207 log.NullLogSink 208 keysAndValues []interface{} 209 } 210 211 // WithValues stores keysAndValues so we can later check if the 212 // right keysAndValues have been added. 213 func (f fakeLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink { 214 f.keysAndValues = keysAndValues 215 return f 216 }