github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/reconciler/grpc_test.go (about) 1 package reconciler 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/operator-framework/api/pkg/operators/v1alpha1" 9 "github.com/sirupsen/logrus" 10 "github.com/stretchr/testify/require" 11 corev1 "k8s.io/api/core/v1" 12 apierrors "k8s.io/apimachinery/pkg/api/errors" 13 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 "k8s.io/apimachinery/pkg/labels" 15 "k8s.io/apimachinery/pkg/runtime" 16 "k8s.io/apimachinery/pkg/types" 17 18 "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" 19 "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/clientfake" 20 ) 21 22 func validGrpcCatalogSource(image, address string) *v1alpha1.CatalogSource { 23 return &v1alpha1.CatalogSource{ 24 ObjectMeta: metav1.ObjectMeta{ 25 Name: "img-catalog", 26 Namespace: testNamespace, 27 UID: "catalog-uid", 28 Labels: map[string]string{"olm.catalogSource": "img-catalog"}, 29 }, 30 Spec: v1alpha1.CatalogSourceSpec{ 31 Image: image, 32 Address: address, 33 SourceType: v1alpha1.SourceTypeGrpc, 34 }, 35 } 36 } 37 38 func grpcCatalogSourceWithSecret(secretNames []string) *v1alpha1.CatalogSource { 39 return &v1alpha1.CatalogSource{ 40 ObjectMeta: metav1.ObjectMeta{ 41 Name: "private-catalog", 42 Namespace: testNamespace, 43 UID: types.UID("catalog-uid"), 44 Labels: map[string]string{"olm.catalogSource": "img-catalog"}, 45 }, 46 Spec: v1alpha1.CatalogSourceSpec{ 47 Image: "private-image", 48 Address: "", 49 SourceType: v1alpha1.SourceTypeGrpc, 50 Secrets: secretNames, 51 }, 52 } 53 } 54 func grpcCatalogSourceWithStatus(status v1alpha1.CatalogSourceStatus) *v1alpha1.CatalogSource { 55 catsrc := validGrpcCatalogSource("image", "") 56 catsrc.Status = status 57 return catsrc 58 } 59 60 func grpcCatalogSourceWithAnnotations(annotations map[string]string) *v1alpha1.CatalogSource { 61 catsrc := validGrpcCatalogSource("image", "") 62 catsrc.ObjectMeta.Annotations = annotations 63 return catsrc 64 } 65 66 func grpcCatalogSourceWithName(name string) *v1alpha1.CatalogSource { 67 catsrc := validGrpcCatalogSource("image", "") 68 catsrc.SetName(name) 69 catsrc.ObjectMeta.Labels["olm.catalogSource"] = name 70 return catsrc 71 } 72 73 func withPodDeletedButNotRemoved(objs []runtime.Object) []runtime.Object { 74 var out []runtime.Object 75 for _, obj := range objs { 76 o := obj.DeepCopyObject() 77 if pod, ok := obj.(*corev1.Pod); ok { 78 pod.DeletionTimestamp = &metav1.Time{Time: time.Now()} 79 pod.Status.Conditions = append(pod.Status.Conditions, corev1.PodCondition{ 80 Type: corev1.DisruptionTarget, 81 Reason: "DeletionByTaintManager", 82 Status: corev1.ConditionTrue, 83 }) 84 o = pod 85 } 86 out = append(out, o) 87 } 88 return out 89 } 90 func TestGrpcRegistryReconciler(t *testing.T) { 91 now := func() metav1.Time { return metav1.Date(2018, time.January, 26, 20, 40, 0, 0, time.UTC) } 92 blockOwnerDeletion := true 93 isController := true 94 95 // We expect the empty string secret name should not be set 96 // on the service account 97 testSecrets := []string{"test-secret", ""} 98 99 type cluster struct { 100 k8sObjs []runtime.Object 101 } 102 type in struct { 103 cluster cluster 104 catsrc *v1alpha1.CatalogSource 105 } 106 type out struct { 107 status *v1alpha1.RegistryServiceStatus 108 cluster cluster 109 err error 110 } 111 tests := []struct { 112 testName string 113 in in 114 out out 115 }{ 116 { 117 testName: "Grpc/NoExistingRegistry/CreateSuccessful", 118 in: in{ 119 cluster: cluster{ 120 k8sObjs: baseClusterState(), 121 }, 122 catsrc: validGrpcCatalogSource("test-img", ""), 123 }, 124 out: out{ 125 status: &v1alpha1.RegistryServiceStatus{ 126 CreatedAt: now(), 127 Protocol: "grpc", 128 ServiceName: "img-catalog", 129 ServiceNamespace: testNamespace, 130 Port: "50051", 131 }, 132 }, 133 }, 134 { 135 testName: "Grpc/NoExistingRegistry/CreateSuccessful/CatalogSourceWithPeriodInNameCreatesValidServiceName", 136 in: in{ 137 cluster: cluster{ 138 k8sObjs: baseClusterState(), 139 }, 140 catsrc: grpcCatalogSourceWithName("img.catalog"), 141 }, 142 out: out{ 143 status: &v1alpha1.RegistryServiceStatus{ 144 CreatedAt: now(), 145 Protocol: "grpc", 146 ServiceName: "img-catalog", 147 ServiceNamespace: testNamespace, 148 Port: "50051", 149 }, 150 }, 151 }, 152 { 153 testName: "Grpc/ExistingRegistry/CreateSuccessful", 154 in: in{ 155 cluster: cluster{ 156 k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), 157 }, 158 catsrc: validGrpcCatalogSource("test-img", ""), 159 }, 160 out: out{ 161 status: &v1alpha1.RegistryServiceStatus{ 162 CreatedAt: now(), 163 Protocol: "grpc", 164 ServiceName: "img-catalog", 165 ServiceNamespace: testNamespace, 166 Port: "50051", 167 }, 168 }, 169 }, 170 { 171 testName: "Grpc/Address/CreateSuccessful", 172 in: in{ 173 cluster: cluster{ 174 k8sObjs: baseClusterState(), 175 }, 176 catsrc: validGrpcCatalogSource("", "catalog.svc.cluster.local:50001"), 177 }, 178 out: out{ 179 status: &v1alpha1.RegistryServiceStatus{ 180 CreatedAt: now(), 181 Protocol: "grpc", 182 }, 183 }, 184 }, 185 { 186 testName: "Grpc/AddressAndImage/CreateSuccessful", 187 in: in{ 188 cluster: cluster{ 189 k8sObjs: baseClusterState(), 190 }, 191 catsrc: validGrpcCatalogSource("img-catalog", "catalog.svc.cluster.local:50001"), 192 }, 193 out: out{ 194 status: &v1alpha1.RegistryServiceStatus{ 195 CreatedAt: now(), 196 Protocol: "grpc", 197 ServiceName: "img-catalog", 198 ServiceNamespace: testNamespace, 199 Port: "50051", 200 }, 201 }, 202 }, 203 { 204 testName: "Grpc/ExistingRegistry/BadServiceWithWrongHash", 205 in: in{ 206 cluster: cluster{ 207 k8sObjs: setLabel(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Service{}, ServiceHashLabelKey, "wrongHash"), 208 }, 209 catsrc: validGrpcCatalogSource("test-img", ""), 210 }, 211 out: out{ 212 status: &v1alpha1.RegistryServiceStatus{ 213 CreatedAt: now(), 214 Protocol: "grpc", 215 ServiceName: "img-catalog", 216 ServiceNamespace: testNamespace, 217 Port: "50051", 218 }, 219 }, 220 }, 221 { 222 testName: "Grpc/ExistingRegistry/BadService", 223 in: in{ 224 cluster: cluster{ 225 k8sObjs: modifyObjName(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Service{}, "badName"), 226 }, 227 catsrc: validGrpcCatalogSource("test-img", ""), 228 }, 229 out: out{ 230 status: &v1alpha1.RegistryServiceStatus{ 231 CreatedAt: now(), 232 Protocol: "grpc", 233 ServiceName: "img-catalog", 234 ServiceNamespace: testNamespace, 235 Port: "50051", 236 }, 237 }, 238 }, 239 { 240 testName: "Grpc/ExistingRegistry/BadPod", 241 in: in{ 242 cluster: cluster{ 243 k8sObjs: setLabel(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Pod{}, CatalogSourceLabelKey, ""), 244 }, 245 catsrc: validGrpcCatalogSource("test-img", ""), 246 }, 247 out: out{ 248 status: &v1alpha1.RegistryServiceStatus{ 249 CreatedAt: now(), 250 Protocol: "grpc", 251 ServiceName: "img-catalog", 252 ServiceNamespace: testNamespace, 253 Port: "50051", 254 }, 255 }, 256 }, 257 { 258 testName: "Grpc/ExistingRegistry/OldPod", 259 in: in{ 260 cluster: cluster{ 261 k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("old-img", "")), 262 }, 263 catsrc: validGrpcCatalogSource("new-img", ""), 264 }, 265 out: out{ 266 status: &v1alpha1.RegistryServiceStatus{ 267 CreatedAt: now(), 268 Protocol: "grpc", 269 ServiceName: "img-catalog", 270 ServiceNamespace: testNamespace, 271 Port: "50051", 272 }, 273 }, 274 }, 275 { 276 testName: "Grpc/PrivateRegistry/SAHasSecrets", 277 in: in{ 278 cluster: cluster{ 279 k8sObjs: []runtime.Object{ 280 defaultNamespace(), 281 &corev1.Secret{ 282 ObjectMeta: metav1.ObjectMeta{ 283 Name: "test-secret", 284 Namespace: testNamespace, 285 }, 286 }, 287 }, 288 }, 289 catsrc: grpcCatalogSourceWithSecret(testSecrets), 290 }, 291 out: out{ 292 status: &v1alpha1.RegistryServiceStatus{ 293 CreatedAt: now(), 294 Protocol: "grpc", 295 ServiceName: "private-catalog", 296 ServiceNamespace: testNamespace, 297 Port: "50051", 298 }, 299 cluster: cluster{ 300 k8sObjs: []runtime.Object{ 301 &corev1.ServiceAccount{ 302 ObjectMeta: metav1.ObjectMeta{ 303 Name: "private-catalog", 304 Namespace: testNamespace, 305 Labels: map[string]string{install.OLMManagedLabelKey: install.OLMManagedLabelValue}, 306 OwnerReferences: []metav1.OwnerReference{ 307 { 308 Name: "private-catalog", 309 UID: types.UID("catalog-uid"), 310 Kind: v1alpha1.CatalogSourceKind, 311 APIVersion: v1alpha1.CatalogSourceCRDAPIVersion, 312 BlockOwnerDeletion: &blockOwnerDeletion, 313 Controller: &isController, 314 }, 315 }, 316 }, 317 ImagePullSecrets: []corev1.LocalObjectReference{ 318 { 319 Name: "test-secret", 320 }, 321 }, 322 }, 323 }, 324 }, 325 }, 326 }, 327 { 328 testName: "Grpc/NoExistingRegistry/CreateWithAnnotations", 329 in: in{ 330 cluster: cluster{ 331 k8sObjs: baseClusterState(), 332 }, 333 catsrc: grpcCatalogSourceWithAnnotations(map[string]string{ 334 "annotation1": "value1", 335 "annotation2": "value2", 336 }), 337 }, 338 out: out{ 339 status: &v1alpha1.RegistryServiceStatus{ 340 CreatedAt: now(), 341 Protocol: "grpc", 342 ServiceName: "img-catalog", 343 ServiceNamespace: testNamespace, 344 Port: "50051", 345 }, 346 }, 347 }, 348 { 349 testName: "Grpc/ExistingRegistry/UpdateInvalidRegistryServiceStatus", 350 in: in{ 351 cluster: cluster{ 352 k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("image", "")), 353 }, 354 catsrc: grpcCatalogSourceWithStatus(v1alpha1.CatalogSourceStatus{ 355 RegistryServiceStatus: &v1alpha1.RegistryServiceStatus{ 356 CreatedAt: now(), 357 Protocol: "grpc", 358 }, 359 }), 360 }, 361 out: out{ 362 status: &v1alpha1.RegistryServiceStatus{ 363 CreatedAt: now(), 364 Protocol: "grpc", 365 ServiceName: "img-catalog", 366 ServiceNamespace: testNamespace, 367 Port: "50051", 368 }, 369 }, 370 }, 371 } 372 for _, tt := range tests { 373 t.Run(tt.testName, func(t *testing.T) { 374 stopc := make(chan struct{}) 375 defer close(stopc) 376 377 factory, client := fakeReconcilerFactory(t, stopc, withNow(now), withK8sObjs(tt.in.cluster.k8sObjs...), withK8sClientOptions(clientfake.WithNameGeneration(t))) 378 rec := factory.ReconcilerForSource(tt.in.catsrc) 379 380 err := rec.EnsureRegistryServer(logrus.NewEntry(logrus.New()), tt.in.catsrc) 381 382 require.Equal(t, tt.out.err, err) 383 require.Equal(t, tt.out.status, tt.in.catsrc.Status.RegistryServiceStatus) 384 385 if tt.out.err != nil { 386 return 387 } 388 389 // Check for resource existence 390 decorated := grpcCatalogSourceDecorator{CatalogSource: tt.in.catsrc, createPodAsUser: runAsUser} 391 sa := decorated.ServiceAccount() 392 pod, err := decorated.Pod(sa, defaultPodSecurityConfig) 393 if err != nil { 394 t.Fatal(err) 395 } 396 service, err := decorated.Service() 397 if err != nil { 398 t.Fatal(err) 399 } 400 listOptions := metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{CatalogSourceLabelKey: tt.in.catsrc.GetName()}).String()} 401 outPods, podErr := client.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).List(context.TODO(), listOptions) 402 outService, serviceErr := client.KubernetesInterface().CoreV1().Services(service.GetNamespace()).Get(context.TODO(), service.GetName(), metav1.GetOptions{}) 403 outsa, saerr := client.KubernetesInterface().CoreV1().ServiceAccounts(sa.GetNamespace()).Get(context.TODO(), sa.GetName(), metav1.GetOptions{}) 404 switch rec.(type) { 405 case *GrpcRegistryReconciler: 406 // Should be created by a GrpcRegistryReconciler 407 require.NoError(t, podErr) 408 require.Len(t, outPods.Items, 1) 409 outPod := outPods.Items[0] 410 require.Equal(t, pod.GetGenerateName(), outPod.GetGenerateName()) 411 require.Equal(t, pod.GetLabels(), outPod.GetLabels()) 412 require.Equal(t, pod.GetAnnotations(), outPod.GetAnnotations()) 413 require.Equal(t, pod.Spec, outPod.Spec) 414 require.NoError(t, serviceErr) 415 require.Equal(t, service, outService) 416 require.NoError(t, saerr) 417 if len(tt.in.catsrc.Spec.Secrets) > 0 { 418 require.Equal(t, tt.out.cluster.k8sObjs[0], outsa) 419 } 420 case *GrpcAddressRegistryReconciler: 421 // Should not be created by a GrpcAddressRegistryReconciler 422 require.NoError(t, podErr) 423 require.Len(t, outPods.Items, 0) 424 require.NoError(t, err) 425 require.True(t, apierrors.IsNotFound(serviceErr)) 426 } 427 }) 428 } 429 } 430 431 func TestRegistryPodPriorityClass(t *testing.T) { 432 now := func() metav1.Time { return metav1.Date(2018, time.January, 26, 20, 40, 0, 0, time.UTC) } 433 434 type cluster struct { 435 k8sObjs []runtime.Object 436 } 437 type in struct { 438 cluster cluster 439 catsrc *v1alpha1.CatalogSource 440 } 441 tests := []struct { 442 testName string 443 in in 444 priorityclass string 445 }{ 446 { 447 testName: "Grpc/WithValidPriorityClassAnnotation", 448 in: in{ 449 catsrc: grpcCatalogSourceWithAnnotations(map[string]string{ 450 "operatorframework.io/priorityclass": "system-cluster-critical", 451 }), 452 }, 453 priorityclass: "system-cluster-critical", 454 }, 455 { 456 testName: "Grpc/WithInvalidPriorityClassAnnotation", 457 in: in{ 458 catsrc: grpcCatalogSourceWithAnnotations(map[string]string{ 459 "operatorframework.io/priorityclass": "", 460 }), 461 }, 462 priorityclass: "", 463 }, 464 { 465 testName: "Grpc/WithNoPriorityClassAnnotation", 466 in: in{ 467 catsrc: grpcCatalogSourceWithAnnotations(map[string]string{ 468 "annotationkey": "annotationvalue", 469 }), 470 }, 471 priorityclass: "", 472 }, 473 } 474 for _, tt := range tests { 475 t.Run(tt.testName, func(t *testing.T) { 476 stopc := make(chan struct{}) 477 defer close(stopc) 478 479 // a defaultNamespace resource must be present so that the reconciler can determine the 480 // security context configuration for the underlying pod 481 clusterState := append(tt.in.cluster.k8sObjs, defaultNamespace()) 482 483 factory, client := fakeReconcilerFactory(t, stopc, withNow(now), withK8sObjs(clusterState...), withK8sClientOptions(clientfake.WithNameGeneration(t))) 484 rec := factory.ReconcilerForSource(tt.in.catsrc) 485 486 err := rec.EnsureRegistryServer(logrus.NewEntry(logrus.New()), tt.in.catsrc) 487 require.NoError(t, err) 488 489 // Check for resource existence 490 decorated := grpcCatalogSourceDecorator{CatalogSource: tt.in.catsrc, createPodAsUser: runAsUser} 491 pod, err := decorated.Pod(serviceAccount(tt.in.catsrc.Namespace, tt.in.catsrc.Name), defaultPodSecurityConfig) 492 require.NoError(t, err) 493 listOptions := metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{CatalogSourceLabelKey: tt.in.catsrc.GetName()}).String()} 494 outPods, podErr := client.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).List(context.TODO(), listOptions) 495 require.NoError(t, podErr) 496 require.Len(t, outPods.Items, 1) 497 outPod := outPods.Items[0] 498 require.Equal(t, tt.priorityclass, outPod.Spec.PriorityClassName) 499 require.Equal(t, pod.GetLabels()[PodHashLabelKey], outPod.GetLabels()[PodHashLabelKey]) 500 }) 501 } 502 } 503 504 func TestGrpcRegistryChecker(t *testing.T) { 505 type cluster struct { 506 k8sObjs []runtime.Object 507 } 508 type in struct { 509 cluster cluster 510 catsrc *v1alpha1.CatalogSource 511 } 512 type out struct { 513 healthy bool 514 err error 515 } 516 tests := []struct { 517 testName string 518 in in 519 out out 520 }{ 521 { 522 testName: "Grpc/ExistingRegistry/Image/Healthy", 523 in: in{ 524 cluster: cluster{ 525 k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), 526 }, 527 catsrc: validGrpcCatalogSource("test-img", ""), 528 }, 529 out: out{ 530 healthy: true, 531 }, 532 }, 533 { 534 testName: "Grpc/NoExistingRegistry/Image/NotHealthy", 535 in: in{ 536 catsrc: validGrpcCatalogSource("test-img", ""), 537 }, 538 out: out{ 539 healthy: false, 540 }, 541 }, 542 { 543 testName: "Grpc/ExistingRegistry/Image/BadService", 544 in: in{ 545 cluster: cluster{ 546 k8sObjs: modifyObjName(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Service{}, "badName"), 547 }, 548 catsrc: validGrpcCatalogSource("test-img", ""), 549 }, 550 out: out{ 551 healthy: false, 552 }, 553 }, 554 { 555 testName: "Grpc/ExistingRegistry/Image/BadServiceAccount", 556 in: in{ 557 cluster: cluster{ 558 k8sObjs: modifyObjName(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.ServiceAccount{}, "badName"), 559 }, 560 catsrc: validGrpcCatalogSource("test-img", ""), 561 }, 562 out: out{ 563 healthy: false, 564 }, 565 }, 566 { 567 testName: "Grpc/ExistingRegistry/Image/BadPod", 568 in: in{ 569 cluster: cluster{ 570 k8sObjs: setLabel(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Pod{}, CatalogSourceLabelKey, ""), 571 }, 572 catsrc: validGrpcCatalogSource("test-img", ""), 573 }, 574 out: out{ 575 healthy: false, 576 }, 577 }, 578 { 579 testName: "Grpc/ExistingRegistry/Image/DeadPod", 580 in: in{ 581 cluster: cluster{ 582 k8sObjs: withPodDeletedButNotRemoved(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", ""))), 583 }, 584 catsrc: validGrpcCatalogSource("test-img", ""), 585 }, 586 out: out{ 587 healthy: false, 588 }, 589 }, 590 { 591 testName: "Grpc/ExistingRegistry/Image/OldPod/NotHealthy", 592 in: in{ 593 cluster: cluster{ 594 k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("old-img", "")), 595 }, 596 catsrc: validGrpcCatalogSource("new-img", ""), 597 }, 598 out: out{ 599 healthy: false, 600 }, 601 }, 602 { 603 testName: "Grpc/NoExistingRegistry/Address/Healthy", 604 in: in{ 605 catsrc: validGrpcCatalogSource("", "catalog.svc.cluster.local:50001"), 606 }, 607 out: out{ 608 healthy: true, 609 }, 610 }, 611 { 612 testName: "Grpc/ExistingRegistry/AddressAndImage/Healthy", 613 in: in{ 614 cluster: cluster{ 615 k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("img-catalog", "catalog.svc.cluster.local:50001")), 616 }, 617 catsrc: validGrpcCatalogSource("img-catalog", "catalog.svc.cluster.local:50001"), 618 }, 619 out: out{ 620 healthy: true, 621 }, 622 }, 623 { 624 testName: "Grpc/NoExistingRegistry/AddressAndImage/NotHealthy", 625 in: in{ 626 catsrc: validGrpcCatalogSource("img-catalog", "catalog.svc.cluster.local:50001"), 627 }, 628 out: out{ 629 healthy: false, 630 }, 631 }, 632 { 633 testName: "Grpc/ExistingRegistry/AddressAndImage/BadService/NotHealthy", 634 in: in{ 635 cluster: cluster{ 636 k8sObjs: modifyObjName(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "catalog.svc.cluster.local:50001")), &corev1.Service{}, "badName"), 637 }, 638 catsrc: validGrpcCatalogSource("test-img", "catalog.svc.cluster.local:50001"), 639 }, 640 out: out{ 641 healthy: false, 642 }, 643 }, 644 { 645 testName: "Grpc/ExistingRegistry/AddressAndImage/OldPod/NotHealthy", 646 in: in{ 647 cluster: cluster{ 648 k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("old-img", "catalog.svc.cluster.local:50001")), 649 }, 650 catsrc: validGrpcCatalogSource("new-img", "catalog.svc.cluster.local:50001"), 651 }, 652 out: out{ 653 healthy: false, 654 }, 655 }, 656 } 657 for _, tt := range tests { 658 t.Run(tt.testName, func(t *testing.T) { 659 stopc := make(chan struct{}) 660 defer close(stopc) 661 662 factory, _ := fakeReconcilerFactory(t, stopc, withK8sObjs(tt.in.cluster.k8sObjs...)) 663 rec := factory.ReconcilerForSource(tt.in.catsrc) 664 665 healthy, err := rec.CheckRegistryServer(logrus.NewEntry(logrus.New()), tt.in.catsrc) 666 667 require.Equal(t, tt.out.err, err) 668 if tt.out.err != nil { 669 return 670 } 671 672 require.Equal(t, tt.out.healthy, healthy) 673 }) 674 } 675 } 676 677 func TestGetPodImageID(t *testing.T) { 678 var table = []struct { 679 description string 680 pod *corev1.Pod 681 result string 682 }{ 683 { 684 description: "default pod has status: return status", 685 pod: &corev1.Pod{Status: corev1.PodStatus{ContainerStatuses: []corev1.ContainerStatus{{ImageID: "xyz123"}}}}, 686 result: "xyz123", 687 }, 688 { 689 description: "extractConfig pod has status: return status", 690 pod: &corev1.Pod{Status: corev1.PodStatus{ 691 InitContainerStatuses: []corev1.ContainerStatus{ 692 {ImageID: "xyz123"}, 693 {ImageID: "abc456"}, 694 }, 695 ContainerStatuses: []corev1.ContainerStatus{ 696 {ImageID: "xyz123"}, 697 }, 698 }}, 699 result: "abc456", 700 }, 701 { 702 description: "pod has unexpected container config", 703 pod: &corev1.Pod{Status: corev1.PodStatus{ContainerStatuses: []corev1.ContainerStatus{ 704 {ImageID: "xyz123"}, 705 {ImageID: "abc456"}, 706 }}}, 707 result: "", 708 }, 709 { 710 description: "pod has no status", 711 pod: &corev1.Pod{Status: corev1.PodStatus{}}, 712 result: "", 713 }, 714 } 715 716 for i, tt := range table { 717 require.Equal(t, tt.result, imageID(tt.pod), table[i].description) 718 } 719 } 720 721 func TestUpdatePodByDigest(t *testing.T) { 722 var table = []struct { 723 description string 724 updatePod *corev1.Pod 725 servingPods []*corev1.Pod 726 result bool 727 }{ 728 { 729 description: "pod image ids match: not update from the registry: return false", 730 updatePod: &corev1.Pod{Status: corev1.PodStatus{ContainerStatuses: []corev1.ContainerStatus{{ImageID: "xyz123"}}}}, 731 servingPods: []*corev1.Pod{{Status: corev1.PodStatus{ContainerStatuses: []corev1.ContainerStatus{{ImageID: "xyz123"}}}}}, 732 result: false, 733 }, 734 { 735 description: "pod image ids do not match: update on the registry: return true", 736 updatePod: &corev1.Pod{Status: corev1.PodStatus{ContainerStatuses: []corev1.ContainerStatus{{ImageID: "abc456"}}}}, 737 servingPods: []*corev1.Pod{{Status: corev1.PodStatus{ContainerStatuses: []corev1.ContainerStatus{{ImageID: "xyz123"}}}}}, 738 result: true, 739 }, 740 } 741 742 for i, tt := range table { 743 require.Equal(t, tt.result, imageChanged(logrus.NewEntry(logrus.New()), tt.updatePod, tt.servingPods), table[i].description) 744 } 745 }