k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/util/controlled_pods_indexer_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 util 18 19 import ( 20 "context" 21 "testing" 22 "time" 23 24 "github.com/stretchr/testify/assert" 25 appsv1 "k8s.io/api/apps/v1" 26 corev1 "k8s.io/api/core/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 29 "k8s.io/apimachinery/pkg/runtime" 30 "k8s.io/apimachinery/pkg/types" 31 "k8s.io/client-go/informers" 32 "k8s.io/client-go/kubernetes/fake" 33 ) 34 35 const ( 36 ns1 = "namespace-1" 37 ) 38 39 var ( 40 daemonsetKind = appsv1.SchemeGroupVersion.WithKind("DaemonSet") 41 replicaSetKind = appsv1.SchemeGroupVersion.WithKind("ReplicaSet") 42 deploymentKind = appsv1.SchemeGroupVersion.WithKind("Deployment") 43 podKind = corev1.SchemeGroupVersion.WithKind("Pod") 44 45 daemonset = &appsv1.DaemonSet{ 46 TypeMeta: metav1.TypeMeta{ 47 APIVersion: daemonsetKind.GroupVersion().String(), 48 Kind: daemonsetKind.Kind, 49 }, 50 ObjectMeta: metav1.ObjectMeta{ 51 Name: "daemonset-1", 52 Namespace: ns1, 53 UID: types.UID("uid-1"), 54 }, 55 } 56 deployment = &appsv1.Deployment{ 57 TypeMeta: metav1.TypeMeta{ 58 APIVersion: deploymentKind.GroupVersion().String(), 59 Kind: deploymentKind.Kind, 60 }, 61 ObjectMeta: metav1.ObjectMeta{ 62 Name: "deployment-1", 63 Namespace: ns1, 64 UID: types.UID("uid-2"), 65 }, 66 } 67 68 replicaSet1 = &appsv1.ReplicaSet{ 69 TypeMeta: metav1.TypeMeta{ 70 APIVersion: replicaSetKind.GroupVersion().String(), 71 Kind: replicaSetKind.Kind, 72 }, 73 ObjectMeta: metav1.ObjectMeta{ 74 Name: "rs-1", 75 Namespace: ns1, 76 UID: types.UID("uid-3"), 77 OwnerReferences: []metav1.OwnerReference{ 78 *metav1.NewControllerRef(deployment, deploymentKind), 79 }, 80 }, 81 } 82 replicaSet2 = &appsv1.ReplicaSet{ 83 TypeMeta: metav1.TypeMeta{ 84 APIVersion: replicaSetKind.GroupVersion().String(), 85 Kind: replicaSetKind.Kind, 86 }, 87 ObjectMeta: metav1.ObjectMeta{ 88 Name: "rs-2", 89 Namespace: ns1, 90 UID: types.UID("uid-7"), 91 OwnerReferences: []metav1.OwnerReference{ 92 *metav1.NewControllerRef(deployment, deploymentKind), 93 }, 94 }, 95 } 96 97 daemonsetPod = &corev1.Pod{ 98 TypeMeta: metav1.TypeMeta{ 99 APIVersion: podKind.GroupVersion().String(), 100 Kind: podKind.Kind, 101 }, 102 ObjectMeta: metav1.ObjectMeta{ 103 Name: "pod-1", 104 Namespace: ns1, 105 UID: types.UID("uid-4"), 106 OwnerReferences: []metav1.OwnerReference{ 107 *metav1.NewControllerRef(daemonset, daemonsetKind), 108 }, 109 }, 110 } 111 112 replicaSetPod1 = &corev1.Pod{ 113 ObjectMeta: metav1.ObjectMeta{ 114 Name: "rs-pod-1", 115 Namespace: ns1, 116 UID: types.UID("uid-5"), 117 OwnerReferences: []metav1.OwnerReference{ 118 *metav1.NewControllerRef(replicaSet1, replicaSetKind), 119 }, 120 }, 121 } 122 123 replicaSetPod2 = &corev1.Pod{ 124 ObjectMeta: metav1.ObjectMeta{ 125 Name: "rs-pod-2", 126 Namespace: ns1, 127 UID: types.UID("uid-6"), 128 OwnerReferences: []metav1.OwnerReference{ 129 *metav1.NewControllerRef(replicaSet2, replicaSetKind), 130 }, 131 }, 132 } 133 ) 134 135 func toUnstructured(t *testing.T, obj interface{}) *unstructured.Unstructured { 136 content, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) 137 if err != nil { 138 t.Fatalf("failed to convert %T to unstructured: %v", obj, err) 139 } 140 return &unstructured.Unstructured{Object: content} 141 } 142 143 func newMockedControlledPodsIndexer(ctx context.Context, t *testing.T, client *fake.Clientset) (*ControlledPodsIndexer, error) { 144 informerFactory := informers.NewSharedInformerFactory(client, 0 /* resyncPeriod */) 145 podsInformer := informerFactory.Core().V1().Pods() 146 rsInformer := informerFactory.Apps().V1().ReplicaSets() 147 p, err := NewControlledPodsIndexer(podsInformer, rsInformer) 148 if err != nil { 149 t.Fatalf("failed to create ControlledPodsIndexer instance: %v", err) 150 } 151 informerFactory.Start(ctx.Done()) 152 if !p.WaitForCacheSync(ctx) { 153 t.Fatalf("failed to sync informer") 154 } 155 156 return p, nil 157 } 158 159 func TestControlledPodsIndexer_PodsControlledBy(t *testing.T) { 160 var allObjects = []runtime.Object{daemonset, deployment, replicaSet1, replicaSet2, daemonsetPod, replicaSetPod1, replicaSetPod2} 161 tests := []struct { 162 name string 163 obj interface{} 164 want []*corev1.Pod 165 wantErr bool 166 }{ 167 { 168 name: "daemonset", 169 obj: daemonset, 170 want: []*corev1.Pod{daemonsetPod}, 171 }, 172 { 173 name: "replicaset", 174 obj: replicaSet1, 175 want: []*corev1.Pod{replicaSetPod1}, 176 }, 177 { 178 name: "deployment", 179 obj: deployment, 180 want: []*corev1.Pod{replicaSetPod1, replicaSetPod2}, 181 }, 182 { 183 // When we fetch objects using dynamic informer, objects are returend as unstructured. 184 // We expect result to be the same as for static-typed deployment. 185 name: "deployment as unstructured", 186 obj: toUnstructured(t, deployment), 187 want: []*corev1.Pod{replicaSetPod1, replicaSetPod2}, 188 }, 189 { 190 name: "daemonset as unstructured", 191 obj: toUnstructured(t, daemonset), 192 want: []*corev1.Pod{daemonsetPod}, 193 }, 194 { 195 name: "unknown type", 196 obj: "string doesn't implement metav1.Object", 197 wantErr: true, 198 }, 199 } 200 for _, tt := range tests { 201 t.Run(tt.name, func(t *testing.T) { 202 ctx, cancel := context.WithCancel(context.Background()) 203 defer cancel() 204 205 fakeClient := fake.NewSimpleClientset(allObjects...) 206 p, err := newMockedControlledPodsIndexer(ctx, t, fakeClient) 207 if err != nil { 208 t.Fatalf("failed to create ControlledPodsIndexer instance: %v", err) 209 } 210 211 got, err := p.PodsControlledBy(tt.obj) 212 if (err != nil) != tt.wantErr { 213 t.Errorf("PodsIndexer.PodsControlledBy() error = %v, wantErr %v", err, tt.wantErr) 214 return 215 } 216 assert.ElementsMatch(t, got, tt.want) 217 }) 218 } 219 } 220 221 func TestControlledPodsIndexer_PodsControlledBy_ReplicasetDeleted(t *testing.T) { 222 ctx, cancel := context.WithCancel(context.Background()) 223 defer cancel() 224 225 fakeClient := fake.NewSimpleClientset(deployment, replicaSet1, replicaSetPod1) 226 p, err := newMockedControlledPodsIndexer(ctx, t, fakeClient) 227 if err != nil { 228 t.Fatalf("failed to create ControlledPodsIndexer instance: %v", err) 229 } 230 231 if err := fakeClient.AppsV1().Deployments(ns1).Delete(ctx, deployment.Name, metav1.DeleteOptions{}); err != nil { 232 t.Fatalf("unexpected error during deployment deletion: %v", err) 233 } 234 if err := fakeClient.AppsV1().ReplicaSets(ns1).Delete(ctx, replicaSet1.Name, metav1.DeleteOptions{}); err != nil { 235 t.Fatalf("unexpected error during replicaset deletion: %v", err) 236 } 237 238 // Sleeping in order for the replicaset informer to catch up with the changes. 239 time.Sleep(1 * time.Second) 240 241 _, exists, err := p.rsIndexer.GetByKey(string(replicaSet1.UID)) 242 if err != nil { 243 t.Fatalf("unexpected error while getting replicaset: %v", err) 244 } 245 246 if !exists { 247 t.Errorf("expected replicaSet to exists in store at this point, but exists=%v", exists) 248 } 249 250 want := []*corev1.Pod{replicaSetPod1} 251 got, err := p.PodsControlledBy(deployment) 252 if err != nil { 253 t.Errorf("PodsIndexer.PodsControlledBy() error = %v, wantErr %v", err, nil) 254 return 255 } 256 257 assert.ElementsMatch(t, got, want) 258 259 if err := fakeClient.CoreV1().Pods(ns1).Delete(ctx, replicaSetPod1.Name, metav1.DeleteOptions{}); err != nil { 260 t.Fatalf("unexpected error during pod deletion: %v", err) 261 } 262 263 // Sleeping in order for the pod informer to catch up with the changes. 264 time.Sleep(1 * time.Second) 265 266 _, exists, err = p.rsIndexer.GetByKey(string(replicaSet1.UID)) 267 if err != nil { 268 t.Fatalf("unexpected error while getting replicaset: %v", err) 269 } 270 271 if exists { 272 t.Errorf("expected replicaSet to be deleted in store at this point, but exists=%v", exists) 273 } 274 } 275 276 func TestControlledPodsIndexer_PodsControlledBy_PodUpdate(t *testing.T) { 277 ctx, cancel := context.WithCancel(context.Background()) 278 defer cancel() 279 280 fakeClient := fake.NewSimpleClientset(deployment, replicaSet1, replicaSetPod1) 281 p, err := newMockedControlledPodsIndexer(ctx, t, fakeClient) 282 if err != nil { 283 t.Fatalf("failed to create ControlledPodsIndexer instance: %v", err) 284 } 285 286 if err := fakeClient.AppsV1().Deployments(ns1).Delete(ctx, deployment.Name, metav1.DeleteOptions{}); err != nil { 287 t.Fatalf("unexpected error during deployment deletion: %v", err) 288 } 289 if err := fakeClient.AppsV1().ReplicaSets(ns1).Delete(ctx, replicaSet1.Name, metav1.DeleteOptions{}); err != nil { 290 t.Fatalf("unexpected error during replicaset deletion: %v", err) 291 } 292 293 // Sleeping in order for the replicaset informer to catch up with the changes. 294 time.Sleep(1 * time.Second) 295 296 changedReplicaSetPod := replicaSetPod1.DeepCopy() 297 changedReplicaSetPod.Status.Phase = "Running" 298 if _, err := fakeClient.CoreV1().Pods(ns1).Update(ctx, changedReplicaSetPod, metav1.UpdateOptions{}); err != nil { 299 t.Fatalf("unexpected error during pod update: %v", err) 300 } 301 302 // Sleeping in order for the pod informer to catch up with the changes. 303 time.Sleep(1 * time.Second) 304 305 want := []*corev1.Pod{changedReplicaSetPod.DeepCopy()} 306 got, err := p.PodsControlledBy(deployment) 307 if err != nil { 308 t.Errorf("PodsIndexer.PodsControlledBy() error = %v, wantErr %v", err, nil) 309 return 310 } 311 312 assert.ElementsMatch(t, got, want) 313 } 314 315 func TestControlledPodsIndexer_PodsControlledBy_PodUpdateUID(t *testing.T) { 316 ctx, cancel := context.WithCancel(context.Background()) 317 defer cancel() 318 319 fakeClient := fake.NewSimpleClientset(deployment, replicaSet1, replicaSetPod1) 320 p, err := newMockedControlledPodsIndexer(ctx, t, fakeClient) 321 if err != nil { 322 t.Fatalf("failed to create ControlledPodsIndexer instance: %v", err) 323 } 324 325 if err := fakeClient.AppsV1().Deployments(ns1).Delete(ctx, deployment.Name, metav1.DeleteOptions{}); err != nil { 326 t.Fatalf("unexpected error during deployment deletion: %v", err) 327 } 328 if err := fakeClient.AppsV1().ReplicaSets(ns1).Delete(ctx, replicaSet1.Name, metav1.DeleteOptions{}); err != nil { 329 t.Fatalf("unexpected error during replicaset deletion: %v", err) 330 } 331 332 // Sleeping in order for the replicaset informer to catch up with the changes. 333 time.Sleep(1 * time.Second) 334 335 changedReplicaSetPod := replicaSetPod1.DeepCopy() 336 changedReplicaSetPod.ObjectMeta.OwnerReferences = []metav1.OwnerReference{ 337 { 338 UID: "some-other-uid", 339 }, 340 } 341 if _, err := fakeClient.CoreV1().Pods(ns1).Update(ctx, changedReplicaSetPod, metav1.UpdateOptions{}); err != nil { 342 t.Fatalf("unexpected error during pod update: %v", err) 343 } 344 345 // Sleeping in order for the pod informer to catch up with the changes. 346 time.Sleep(1 * time.Second) 347 348 want := []*corev1.Pod{} 349 got, err := p.PodsControlledBy(deployment) 350 if err != nil { 351 t.Errorf("PodsIndexer.PodsControlledBy() error = %v, wantErr %v", err, nil) 352 return 353 } 354 355 assert.ElementsMatch(t, got, want) 356 357 _, exists, err := p.rsIndexer.GetByKey(string(replicaSet1.UID)) 358 if err != nil { 359 t.Fatalf("unexpected error while getting replicaset: %v", err) 360 } 361 362 if exists { 363 t.Errorf("expected replicaSet to be deleted in store at this point, but exists=%v", exists) 364 } 365 }