...

Source file src/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler_test.go

Documentation: sigs.k8s.io/controller-runtime/pkg/handler

     1  /*
     2  	Copyright 2018 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 handler_test
    18  
    19  import (
    20  	"context"
    21  
    22  	. "github.com/onsi/ginkgo/v2"
    23  	. "github.com/onsi/gomega"
    24  	appsv1 "k8s.io/api/apps/v1"
    25  	autoscalingv1 "k8s.io/api/autoscaling/v1"
    26  	corev1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/api/meta"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/types"
    30  	"k8s.io/client-go/kubernetes/scheme"
    31  	"k8s.io/client-go/rest"
    32  	"k8s.io/client-go/util/workqueue"
    33  	"k8s.io/utils/ptr"
    34  	"sigs.k8s.io/controller-runtime/pkg/client"
    35  	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
    36  	"sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
    37  	"sigs.k8s.io/controller-runtime/pkg/event"
    38  	"sigs.k8s.io/controller-runtime/pkg/handler"
    39  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    40  )
    41  
    42  var _ = Describe("Eventhandler", func() {
    43  	var ctx = context.Background()
    44  	var q workqueue.RateLimitingInterface
    45  	var instance handler.EnqueueRequestForObject
    46  	var pod *corev1.Pod
    47  	var mapper meta.RESTMapper
    48  	BeforeEach(func() {
    49  		q = &controllertest.Queue{Interface: workqueue.New()}
    50  		pod = &corev1.Pod{
    51  			ObjectMeta: metav1.ObjectMeta{Namespace: "biz", Name: "baz"},
    52  		}
    53  		Expect(cfg).NotTo(BeNil())
    54  
    55  		httpClient, err := rest.HTTPClientFor(cfg)
    56  		Expect(err).ShouldNot(HaveOccurred())
    57  		mapper, err = apiutil.NewDynamicRESTMapper(cfg, httpClient)
    58  		Expect(err).ShouldNot(HaveOccurred())
    59  	})
    60  
    61  	Describe("EnqueueRequestForObject", func() {
    62  		It("should enqueue a Request with the Name / Namespace of the object in the CreateEvent.", func() {
    63  			evt := event.CreateEvent{
    64  				Object: pod,
    65  			}
    66  			instance.Create(ctx, evt, q)
    67  			Expect(q.Len()).To(Equal(1))
    68  
    69  			i, _ := q.Get()
    70  			Expect(i).NotTo(BeNil())
    71  			req, ok := i.(reconcile.Request)
    72  			Expect(ok).To(BeTrue())
    73  			Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz", Name: "baz"}))
    74  		})
    75  
    76  		It("should enqueue a Request with the Name / Namespace of the object in the DeleteEvent.", func() {
    77  			evt := event.DeleteEvent{
    78  				Object: pod,
    79  			}
    80  			instance.Delete(ctx, evt, q)
    81  			Expect(q.Len()).To(Equal(1))
    82  
    83  			i, _ := q.Get()
    84  			Expect(i).NotTo(BeNil())
    85  			req, ok := i.(reconcile.Request)
    86  			Expect(ok).To(BeTrue())
    87  			Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz", Name: "baz"}))
    88  		})
    89  
    90  		It("should enqueue a Request with the Name / Namespace of one object in the UpdateEvent.",
    91  			func() {
    92  				newPod := pod.DeepCopy()
    93  				newPod.Name = "baz2"
    94  				newPod.Namespace = "biz2"
    95  
    96  				evt := event.UpdateEvent{
    97  					ObjectOld: pod,
    98  					ObjectNew: newPod,
    99  				}
   100  				instance.Update(ctx, evt, q)
   101  				Expect(q.Len()).To(Equal(1))
   102  
   103  				i, _ := q.Get()
   104  				Expect(i).NotTo(BeNil())
   105  				req, ok := i.(reconcile.Request)
   106  				Expect(ok).To(BeTrue())
   107  				Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz2", Name: "baz2"}))
   108  			})
   109  
   110  		It("should enqueue a Request with the Name / Namespace of the object in the GenericEvent.", func() {
   111  			evt := event.GenericEvent{
   112  				Object: pod,
   113  			}
   114  			instance.Generic(ctx, evt, q)
   115  			Expect(q.Len()).To(Equal(1))
   116  			i, _ := q.Get()
   117  			Expect(i).NotTo(BeNil())
   118  			req, ok := i.(reconcile.Request)
   119  			Expect(ok).To(BeTrue())
   120  			Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz", Name: "baz"}))
   121  		})
   122  
   123  		Context("for a runtime.Object without Object", func() {
   124  			It("should do nothing if the Object is missing for a CreateEvent.", func() {
   125  				evt := event.CreateEvent{
   126  					Object: nil,
   127  				}
   128  				instance.Create(ctx, evt, q)
   129  				Expect(q.Len()).To(Equal(0))
   130  			})
   131  
   132  			It("should do nothing if the Object is missing for a UpdateEvent.", func() {
   133  				newPod := pod.DeepCopy()
   134  				newPod.Name = "baz2"
   135  				newPod.Namespace = "biz2"
   136  
   137  				evt := event.UpdateEvent{
   138  					ObjectNew: newPod,
   139  					ObjectOld: nil,
   140  				}
   141  				instance.Update(ctx, evt, q)
   142  				Expect(q.Len()).To(Equal(1))
   143  				i, _ := q.Get()
   144  				Expect(i).NotTo(BeNil())
   145  				req, ok := i.(reconcile.Request)
   146  				Expect(ok).To(BeTrue())
   147  				Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz2", Name: "baz2"}))
   148  
   149  				evt.ObjectNew = nil
   150  				evt.ObjectOld = pod
   151  				instance.Update(ctx, evt, q)
   152  				Expect(q.Len()).To(Equal(1))
   153  				i, _ = q.Get()
   154  				Expect(i).NotTo(BeNil())
   155  				req, ok = i.(reconcile.Request)
   156  				Expect(ok).To(BeTrue())
   157  				Expect(req.NamespacedName).To(Equal(types.NamespacedName{Namespace: "biz", Name: "baz"}))
   158  			})
   159  
   160  			It("should do nothing if the Object is missing for a DeleteEvent.", func() {
   161  				evt := event.DeleteEvent{
   162  					Object: nil,
   163  				}
   164  				instance.Delete(ctx, evt, q)
   165  				Expect(q.Len()).To(Equal(0))
   166  			})
   167  
   168  			It("should do nothing if the Object is missing for a GenericEvent.", func() {
   169  				evt := event.GenericEvent{
   170  					Object: nil,
   171  				}
   172  				instance.Generic(ctx, evt, q)
   173  				Expect(q.Len()).To(Equal(0))
   174  			})
   175  		})
   176  	})
   177  
   178  	Describe("EnqueueRequestsFromMapFunc", func() {
   179  		It("should enqueue a Request with the function applied to the CreateEvent.", func() {
   180  			req := []reconcile.Request{}
   181  			instance := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
   182  				defer GinkgoRecover()
   183  				Expect(a).To(Equal(pod))
   184  				req = []reconcile.Request{
   185  					{
   186  						NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"},
   187  					},
   188  					{
   189  						NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"},
   190  					},
   191  				}
   192  				return req
   193  			})
   194  
   195  			evt := event.CreateEvent{
   196  				Object: pod,
   197  			}
   198  			instance.Create(ctx, evt, q)
   199  			Expect(q.Len()).To(Equal(2))
   200  
   201  			i1, _ := q.Get()
   202  			i2, _ := q.Get()
   203  			Expect([]interface{}{i1, i2}).To(ConsistOf(
   204  				reconcile.Request{
   205  					NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}},
   206  				reconcile.Request{
   207  					NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"}},
   208  			))
   209  		})
   210  
   211  		It("should enqueue a Request with the function applied to the DeleteEvent.", func() {
   212  			req := []reconcile.Request{}
   213  			instance := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
   214  				defer GinkgoRecover()
   215  				Expect(a).To(Equal(pod))
   216  				req = []reconcile.Request{
   217  					{
   218  						NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"},
   219  					},
   220  					{
   221  						NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"},
   222  					},
   223  				}
   224  				return req
   225  			})
   226  
   227  			evt := event.DeleteEvent{
   228  				Object: pod,
   229  			}
   230  			instance.Delete(ctx, evt, q)
   231  			Expect(q.Len()).To(Equal(2))
   232  
   233  			i1, _ := q.Get()
   234  			i2, _ := q.Get()
   235  			Expect([]interface{}{i1, i2}).To(ConsistOf(
   236  				reconcile.Request{
   237  					NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}},
   238  				reconcile.Request{
   239  					NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"}},
   240  			))
   241  		})
   242  
   243  		It("should enqueue a Request with the function applied to both objects in the UpdateEvent.",
   244  			func() {
   245  				newPod := pod.DeepCopy()
   246  
   247  				req := []reconcile.Request{}
   248  
   249  				instance := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
   250  					defer GinkgoRecover()
   251  					req = []reconcile.Request{
   252  						{
   253  							NamespacedName: types.NamespacedName{Namespace: "foo", Name: a.GetName() + "-bar"},
   254  						},
   255  						{
   256  							NamespacedName: types.NamespacedName{Namespace: "biz", Name: a.GetName() + "-baz"},
   257  						},
   258  					}
   259  					return req
   260  				})
   261  
   262  				evt := event.UpdateEvent{
   263  					ObjectOld: pod,
   264  					ObjectNew: newPod,
   265  				}
   266  				instance.Update(ctx, evt, q)
   267  				Expect(q.Len()).To(Equal(2))
   268  
   269  				i, _ := q.Get()
   270  				Expect(i).To(Equal(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "foo", Name: "baz-bar"}}))
   271  
   272  				i, _ = q.Get()
   273  				Expect(i).To(Equal(reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz-baz"}}))
   274  			})
   275  
   276  		It("should enqueue a Request with the function applied to the GenericEvent.", func() {
   277  			req := []reconcile.Request{}
   278  			instance := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request {
   279  				defer GinkgoRecover()
   280  				Expect(a).To(Equal(pod))
   281  				req = []reconcile.Request{
   282  					{
   283  						NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"},
   284  					},
   285  					{
   286  						NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"},
   287  					},
   288  				}
   289  				return req
   290  			})
   291  
   292  			evt := event.GenericEvent{
   293  				Object: pod,
   294  			}
   295  			instance.Generic(ctx, evt, q)
   296  			Expect(q.Len()).To(Equal(2))
   297  
   298  			i1, _ := q.Get()
   299  			i2, _ := q.Get()
   300  			Expect([]interface{}{i1, i2}).To(ConsistOf(
   301  				reconcile.Request{
   302  					NamespacedName: types.NamespacedName{Namespace: "foo", Name: "bar"}},
   303  				reconcile.Request{
   304  					NamespacedName: types.NamespacedName{Namespace: "biz", Name: "baz"}},
   305  			))
   306  		})
   307  	})
   308  
   309  	Describe("EnqueueRequestForOwner", func() {
   310  		It("should enqueue a Request with the Owner of the object in the CreateEvent.", func() {
   311  			instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
   312  
   313  			pod.OwnerReferences = []metav1.OwnerReference{
   314  				{
   315  					Name:       "foo-parent",
   316  					Kind:       "ReplicaSet",
   317  					APIVersion: "apps/v1",
   318  				},
   319  			}
   320  			evt := event.CreateEvent{
   321  				Object: pod,
   322  			}
   323  			instance.Create(ctx, evt, q)
   324  			Expect(q.Len()).To(Equal(1))
   325  
   326  			i, _ := q.Get()
   327  			Expect(i).To(Equal(reconcile.Request{
   328  				NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
   329  		})
   330  
   331  		It("should enqueue a Request with the Owner of the object in the DeleteEvent.", func() {
   332  			instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
   333  
   334  			pod.OwnerReferences = []metav1.OwnerReference{
   335  				{
   336  					Name:       "foo-parent",
   337  					Kind:       "ReplicaSet",
   338  					APIVersion: "apps/v1",
   339  				},
   340  			}
   341  			evt := event.DeleteEvent{
   342  				Object: pod,
   343  			}
   344  			instance.Delete(ctx, evt, q)
   345  			Expect(q.Len()).To(Equal(1))
   346  
   347  			i, _ := q.Get()
   348  			Expect(i).To(Equal(reconcile.Request{
   349  				NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
   350  		})
   351  
   352  		It("should enqueue a Request with the Owners of both objects in the UpdateEvent.", func() {
   353  			newPod := pod.DeepCopy()
   354  			newPod.Name = pod.Name + "2"
   355  			newPod.Namespace = pod.Namespace + "2"
   356  
   357  			instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
   358  
   359  			pod.OwnerReferences = []metav1.OwnerReference{
   360  				{
   361  					Name:       "foo1-parent",
   362  					Kind:       "ReplicaSet",
   363  					APIVersion: "apps/v1",
   364  				},
   365  			}
   366  			newPod.OwnerReferences = []metav1.OwnerReference{
   367  				{
   368  					Name:       "foo2-parent",
   369  					Kind:       "ReplicaSet",
   370  					APIVersion: "apps/v1",
   371  				},
   372  			}
   373  			evt := event.UpdateEvent{
   374  				ObjectOld: pod,
   375  				ObjectNew: newPod,
   376  			}
   377  			instance.Update(ctx, evt, q)
   378  			Expect(q.Len()).To(Equal(2))
   379  
   380  			i1, _ := q.Get()
   381  			i2, _ := q.Get()
   382  			Expect([]interface{}{i1, i2}).To(ConsistOf(
   383  				reconcile.Request{
   384  					NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo1-parent"}},
   385  				reconcile.Request{
   386  					NamespacedName: types.NamespacedName{Namespace: newPod.GetNamespace(), Name: "foo2-parent"}},
   387  			))
   388  		})
   389  
   390  		It("should enqueue a Request with the one duplicate Owner of both objects in the UpdateEvent.", func() {
   391  			newPod := pod.DeepCopy()
   392  			newPod.Name = pod.Name + "2"
   393  
   394  			instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
   395  
   396  			pod.OwnerReferences = []metav1.OwnerReference{
   397  				{
   398  					Name:       "foo-parent",
   399  					Kind:       "ReplicaSet",
   400  					APIVersion: "apps/v1",
   401  				},
   402  			}
   403  			newPod.OwnerReferences = []metav1.OwnerReference{
   404  				{
   405  					Name:       "foo-parent",
   406  					Kind:       "ReplicaSet",
   407  					APIVersion: "apps/v1",
   408  				},
   409  			}
   410  			evt := event.UpdateEvent{
   411  				ObjectOld: pod,
   412  				ObjectNew: newPod,
   413  			}
   414  			instance.Update(ctx, evt, q)
   415  			Expect(q.Len()).To(Equal(1))
   416  
   417  			i, _ := q.Get()
   418  			Expect(i).To(Equal(reconcile.Request{
   419  				NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
   420  		})
   421  
   422  		It("should enqueue a Request with the Owner of the object in the GenericEvent.", func() {
   423  			instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
   424  			pod.OwnerReferences = []metav1.OwnerReference{
   425  				{
   426  					Name:       "foo-parent",
   427  					Kind:       "ReplicaSet",
   428  					APIVersion: "apps/v1",
   429  				},
   430  			}
   431  			evt := event.GenericEvent{
   432  				Object: pod,
   433  			}
   434  			instance.Generic(ctx, evt, q)
   435  			Expect(q.Len()).To(Equal(1))
   436  
   437  			i, _ := q.Get()
   438  			Expect(i).To(Equal(reconcile.Request{
   439  				NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
   440  		})
   441  
   442  		It("should not enqueue a Request if there are no owners matching Group and Kind.", func() {
   443  			instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{}, handler.OnlyControllerOwner())
   444  			pod.OwnerReferences = []metav1.OwnerReference{
   445  				{ // Wrong group
   446  					Name:       "foo1-parent",
   447  					Kind:       "ReplicaSet",
   448  					APIVersion: "extensions/v1",
   449  				},
   450  				{ // Wrong kind
   451  					Name:       "foo2-parent",
   452  					Kind:       "Deployment",
   453  					APIVersion: "apps/v1",
   454  				},
   455  			}
   456  			evt := event.CreateEvent{
   457  				Object: pod,
   458  			}
   459  			instance.Create(ctx, evt, q)
   460  			Expect(q.Len()).To(Equal(0))
   461  		})
   462  
   463  		It("should enqueue a Request if there are owners matching Group "+
   464  			"and Kind with a different version.", func() {
   465  			instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &autoscalingv1.HorizontalPodAutoscaler{})
   466  			pod.OwnerReferences = []metav1.OwnerReference{
   467  				{
   468  					Name:       "foo-parent",
   469  					Kind:       "HorizontalPodAutoscaler",
   470  					APIVersion: "autoscaling/v2",
   471  				},
   472  			}
   473  			evt := event.CreateEvent{
   474  				Object: pod,
   475  			}
   476  			instance.Create(ctx, evt, q)
   477  			Expect(q.Len()).To(Equal(1))
   478  
   479  			i, _ := q.Get()
   480  			Expect(i).To(Equal(reconcile.Request{
   481  				NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo-parent"}}))
   482  		})
   483  
   484  		It("should enqueue a Request for a owner that is cluster scoped", func() {
   485  			instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &corev1.Node{})
   486  			pod.OwnerReferences = []metav1.OwnerReference{
   487  				{
   488  					Name:       "node-1",
   489  					Kind:       "Node",
   490  					APIVersion: "v1",
   491  				},
   492  			}
   493  			evt := event.CreateEvent{
   494  				Object: pod,
   495  			}
   496  			instance.Create(ctx, evt, q)
   497  			Expect(q.Len()).To(Equal(1))
   498  
   499  			i, _ := q.Get()
   500  			Expect(i).To(Equal(reconcile.Request{
   501  				NamespacedName: types.NamespacedName{Namespace: "", Name: "node-1"}}))
   502  
   503  		})
   504  
   505  		It("should not enqueue a Request if there are no owners.", func() {
   506  			instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
   507  			evt := event.CreateEvent{
   508  				Object: pod,
   509  			}
   510  			instance.Create(ctx, evt, q)
   511  			Expect(q.Len()).To(Equal(0))
   512  		})
   513  
   514  		Context("with the Controller field set to true", func() {
   515  			It("should enqueue reconcile.Requests for only the first the Controller if there are "+
   516  				"multiple Controller owners.", func() {
   517  				instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{}, handler.OnlyControllerOwner())
   518  				pod.OwnerReferences = []metav1.OwnerReference{
   519  					{
   520  						Name:       "foo1-parent",
   521  						Kind:       "ReplicaSet",
   522  						APIVersion: "apps/v1",
   523  					},
   524  					{
   525  						Name:       "foo2-parent",
   526  						Kind:       "ReplicaSet",
   527  						APIVersion: "apps/v1",
   528  						Controller: ptr.To(true),
   529  					},
   530  					{
   531  						Name:       "foo3-parent",
   532  						Kind:       "ReplicaSet",
   533  						APIVersion: "apps/v1",
   534  					},
   535  					{
   536  						Name:       "foo4-parent",
   537  						Kind:       "ReplicaSet",
   538  						APIVersion: "apps/v1",
   539  						Controller: ptr.To(true),
   540  					},
   541  					{
   542  						Name:       "foo5-parent",
   543  						Kind:       "ReplicaSet",
   544  						APIVersion: "apps/v1",
   545  					},
   546  				}
   547  				evt := event.CreateEvent{
   548  					Object: pod,
   549  				}
   550  				instance.Create(ctx, evt, q)
   551  				Expect(q.Len()).To(Equal(1))
   552  				i, _ := q.Get()
   553  				Expect(i).To(Equal(reconcile.Request{
   554  					NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo2-parent"}}))
   555  			})
   556  
   557  			It("should not enqueue reconcile.Requests if there are no Controller owners.", func() {
   558  				instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{}, handler.OnlyControllerOwner())
   559  				pod.OwnerReferences = []metav1.OwnerReference{
   560  					{
   561  						Name:       "foo1-parent",
   562  						Kind:       "ReplicaSet",
   563  						APIVersion: "apps/v1",
   564  					},
   565  					{
   566  						Name:       "foo2-parent",
   567  						Kind:       "ReplicaSet",
   568  						APIVersion: "apps/v1",
   569  					},
   570  					{
   571  						Name:       "foo3-parent",
   572  						Kind:       "ReplicaSet",
   573  						APIVersion: "apps/v1",
   574  					},
   575  				}
   576  				evt := event.CreateEvent{
   577  					Object: pod,
   578  				}
   579  				instance.Create(ctx, evt, q)
   580  				Expect(q.Len()).To(Equal(0))
   581  			})
   582  
   583  			It("should not enqueue reconcile.Requests if there are no owners.", func() {
   584  				instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{}, handler.OnlyControllerOwner())
   585  				evt := event.CreateEvent{
   586  					Object: pod,
   587  				}
   588  				instance.Create(ctx, evt, q)
   589  				Expect(q.Len()).To(Equal(0))
   590  			})
   591  		})
   592  
   593  		Context("with the Controller field set to false", func() {
   594  			It("should enqueue a reconcile.Requests for all owners.", func() {
   595  				instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
   596  				pod.OwnerReferences = []metav1.OwnerReference{
   597  					{
   598  						Name:       "foo1-parent",
   599  						Kind:       "ReplicaSet",
   600  						APIVersion: "apps/v1",
   601  					},
   602  					{
   603  						Name:       "foo2-parent",
   604  						Kind:       "ReplicaSet",
   605  						APIVersion: "apps/v1",
   606  					},
   607  					{
   608  						Name:       "foo3-parent",
   609  						Kind:       "ReplicaSet",
   610  						APIVersion: "apps/v1",
   611  					},
   612  				}
   613  				evt := event.CreateEvent{
   614  					Object: pod,
   615  				}
   616  				instance.Create(ctx, evt, q)
   617  				Expect(q.Len()).To(Equal(3))
   618  
   619  				i1, _ := q.Get()
   620  				i2, _ := q.Get()
   621  				i3, _ := q.Get()
   622  				Expect([]interface{}{i1, i2, i3}).To(ConsistOf(
   623  					reconcile.Request{
   624  						NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo1-parent"}},
   625  					reconcile.Request{
   626  						NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo2-parent"}},
   627  					reconcile.Request{
   628  						NamespacedName: types.NamespacedName{Namespace: pod.GetNamespace(), Name: "foo3-parent"}},
   629  				))
   630  			})
   631  		})
   632  
   633  		Context("with a nil object", func() {
   634  			It("should do nothing.", func() {
   635  				instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
   636  				pod.OwnerReferences = []metav1.OwnerReference{
   637  					{
   638  						Name:       "foo1-parent",
   639  						Kind:       "ReplicaSet",
   640  						APIVersion: "apps/v1",
   641  					},
   642  				}
   643  				evt := event.CreateEvent{
   644  					Object: nil,
   645  				}
   646  				instance.Create(ctx, evt, q)
   647  				Expect(q.Len()).To(Equal(0))
   648  			})
   649  		})
   650  
   651  		Context("with a nil OwnerType", func() {
   652  			It("should panic", func() {
   653  				Expect(func() {
   654  					handler.EnqueueRequestForOwner(nil, nil, nil)
   655  				}).To(Panic())
   656  			})
   657  		})
   658  
   659  		Context("with an invalid APIVersion in the OwnerReference", func() {
   660  			It("should do nothing.", func() {
   661  				instance := handler.EnqueueRequestForOwner(scheme.Scheme, mapper, &appsv1.ReplicaSet{})
   662  				pod.OwnerReferences = []metav1.OwnerReference{
   663  					{
   664  						Name:       "foo1-parent",
   665  						Kind:       "ReplicaSet",
   666  						APIVersion: "apps/v1/fail",
   667  					},
   668  				}
   669  				evt := event.CreateEvent{
   670  					Object: pod,
   671  				}
   672  				instance.Create(ctx, evt, q)
   673  				Expect(q.Len()).To(Equal(0))
   674  			})
   675  		})
   676  	})
   677  
   678  	Describe("Funcs", func() {
   679  		failingFuncs := handler.Funcs{
   680  			CreateFunc: func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface) {
   681  				defer GinkgoRecover()
   682  				Fail("Did not expect CreateEvent to be called.")
   683  			},
   684  			DeleteFunc: func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface) {
   685  				defer GinkgoRecover()
   686  				Fail("Did not expect DeleteEvent to be called.")
   687  			},
   688  			UpdateFunc: func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface) {
   689  				defer GinkgoRecover()
   690  				Fail("Did not expect UpdateEvent to be called.")
   691  			},
   692  			GenericFunc: func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface) {
   693  				defer GinkgoRecover()
   694  				Fail("Did not expect GenericEvent to be called.")
   695  			},
   696  		}
   697  
   698  		It("should call CreateFunc for a CreateEvent if provided.", func() {
   699  			instance := failingFuncs
   700  			evt := event.CreateEvent{
   701  				Object: pod,
   702  			}
   703  			instance.CreateFunc = func(ctx context.Context, evt2 event.CreateEvent, q2 workqueue.RateLimitingInterface) {
   704  				defer GinkgoRecover()
   705  				Expect(q2).To(Equal(q))
   706  				Expect(evt2).To(Equal(evt))
   707  			}
   708  			instance.Create(ctx, evt, q)
   709  		})
   710  
   711  		It("should NOT call CreateFunc for a CreateEvent if NOT provided.", func() {
   712  			instance := failingFuncs
   713  			instance.CreateFunc = nil
   714  			evt := event.CreateEvent{
   715  				Object: pod,
   716  			}
   717  			instance.Create(ctx, evt, q)
   718  		})
   719  
   720  		It("should call UpdateFunc for an UpdateEvent if provided.", func() {
   721  			newPod := pod.DeepCopy()
   722  			newPod.Name = pod.Name + "2"
   723  			newPod.Namespace = pod.Namespace + "2"
   724  			evt := event.UpdateEvent{
   725  				ObjectOld: pod,
   726  				ObjectNew: newPod,
   727  			}
   728  
   729  			instance := failingFuncs
   730  			instance.UpdateFunc = func(ctx context.Context, evt2 event.UpdateEvent, q2 workqueue.RateLimitingInterface) {
   731  				defer GinkgoRecover()
   732  				Expect(q2).To(Equal(q))
   733  				Expect(evt2).To(Equal(evt))
   734  			}
   735  
   736  			instance.Update(ctx, evt, q)
   737  		})
   738  
   739  		It("should NOT call UpdateFunc for an UpdateEvent if NOT provided.", func() {
   740  			newPod := pod.DeepCopy()
   741  			newPod.Name = pod.Name + "2"
   742  			newPod.Namespace = pod.Namespace + "2"
   743  			evt := event.UpdateEvent{
   744  				ObjectOld: pod,
   745  				ObjectNew: newPod,
   746  			}
   747  			instance.Update(ctx, evt, q)
   748  		})
   749  
   750  		It("should call DeleteFunc for a DeleteEvent if provided.", func() {
   751  			instance := failingFuncs
   752  			evt := event.DeleteEvent{
   753  				Object: pod,
   754  			}
   755  			instance.DeleteFunc = func(ctx context.Context, evt2 event.DeleteEvent, q2 workqueue.RateLimitingInterface) {
   756  				defer GinkgoRecover()
   757  				Expect(q2).To(Equal(q))
   758  				Expect(evt2).To(Equal(evt))
   759  			}
   760  			instance.Delete(ctx, evt, q)
   761  		})
   762  
   763  		It("should NOT call DeleteFunc for a DeleteEvent if NOT provided.", func() {
   764  			instance := failingFuncs
   765  			instance.DeleteFunc = nil
   766  			evt := event.DeleteEvent{
   767  				Object: pod,
   768  			}
   769  			instance.Delete(ctx, evt, q)
   770  		})
   771  
   772  		It("should call GenericFunc for a GenericEvent if provided.", func() {
   773  			instance := failingFuncs
   774  			evt := event.GenericEvent{
   775  				Object: pod,
   776  			}
   777  			instance.GenericFunc = func(ctx context.Context, evt2 event.GenericEvent, q2 workqueue.RateLimitingInterface) {
   778  				defer GinkgoRecover()
   779  				Expect(q2).To(Equal(q))
   780  				Expect(evt2).To(Equal(evt))
   781  			}
   782  			instance.Generic(ctx, evt, q)
   783  		})
   784  
   785  		It("should NOT call GenericFunc for a GenericEvent if NOT provided.", func() {
   786  			instance := failingFuncs
   787  			instance.GenericFunc = nil
   788  			evt := event.GenericEvent{
   789  				Object: pod,
   790  			}
   791  			instance.Generic(ctx, evt, q)
   792  		})
   793  	})
   794  })
   795  

View as plain text