1
16
17 package builder
18
19 import (
20 "context"
21 "fmt"
22 "strings"
23 "sync/atomic"
24
25 "github.com/go-logr/logr"
26 . "github.com/onsi/ginkgo/v2"
27 . "github.com/onsi/gomega"
28 appsv1 "k8s.io/api/apps/v1"
29 corev1 "k8s.io/api/core/v1"
30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 "k8s.io/apimachinery/pkg/runtime"
32 "k8s.io/apimachinery/pkg/runtime/schema"
33 "k8s.io/apimachinery/pkg/types"
34 "k8s.io/client-go/rest"
35 "k8s.io/client-go/util/workqueue"
36 "k8s.io/utils/ptr"
37
38 "sigs.k8s.io/controller-runtime/pkg/cache"
39 "sigs.k8s.io/controller-runtime/pkg/client"
40 "sigs.k8s.io/controller-runtime/pkg/config"
41 "sigs.k8s.io/controller-runtime/pkg/controller"
42 "sigs.k8s.io/controller-runtime/pkg/event"
43 "sigs.k8s.io/controller-runtime/pkg/handler"
44 "sigs.k8s.io/controller-runtime/pkg/manager"
45 "sigs.k8s.io/controller-runtime/pkg/predicate"
46 "sigs.k8s.io/controller-runtime/pkg/reconcile"
47 "sigs.k8s.io/controller-runtime/pkg/scheme"
48 )
49
50 type typedNoop struct{}
51
52 func (typedNoop) Reconcile(context.Context, reconcile.Request) (reconcile.Result, error) {
53 return reconcile.Result{}, nil
54 }
55
56 type testLogger struct {
57 logr.Logger
58 }
59
60 func (l *testLogger) Init(logr.RuntimeInfo) {
61 }
62
63 func (l *testLogger) Enabled(int) bool {
64 return true
65 }
66
67 func (l *testLogger) Info(level int, msg string, keysAndValues ...interface{}) {
68 }
69
70 func (l *testLogger) WithValues(keysAndValues ...interface{}) logr.LogSink {
71 return l
72 }
73
74 func (l *testLogger) WithName(name string) logr.LogSink {
75 return l
76 }
77
78 var _ = Describe("application", func() {
79 BeforeEach(func() {
80 newController = controller.New
81 })
82
83 noop := reconcile.Func(func(context.Context, reconcile.Request) (reconcile.Result, error) {
84 return reconcile.Result{}, nil
85 })
86
87 Describe("New", func() {
88 It("should return success if given valid objects", func() {
89 By("creating a controller manager")
90 m, err := manager.New(cfg, manager.Options{})
91 Expect(err).NotTo(HaveOccurred())
92
93 instance, err := ControllerManagedBy(m).
94 For(&appsv1.ReplicaSet{}).
95 Owns(&appsv1.ReplicaSet{}).
96 Build(noop)
97 Expect(err).NotTo(HaveOccurred())
98 Expect(instance).NotTo(BeNil())
99 })
100
101 It("should return error if given two apiType objects in For function", func() {
102 By("creating a controller manager")
103 m, err := manager.New(cfg, manager.Options{})
104 Expect(err).NotTo(HaveOccurred())
105
106 instance, err := ControllerManagedBy(m).
107 For(&appsv1.ReplicaSet{}).
108 For(&appsv1.Deployment{}).
109 Owns(&appsv1.ReplicaSet{}).
110 Build(noop)
111 Expect(err).To(MatchError(ContainSubstring("For(...) should only be called once, could not assign multiple objects for reconciliation")))
112 Expect(instance).To(BeNil())
113 })
114
115 It("should return an error if For and Named function are not called", func() {
116 By("creating a controller manager")
117 m, err := manager.New(cfg, manager.Options{})
118 Expect(err).NotTo(HaveOccurred())
119
120 instance, err := ControllerManagedBy(m).
121 Watches(&appsv1.ReplicaSet{}, &handler.EnqueueRequestForObject{}).
122 Build(noop)
123 Expect(err).To(MatchError(ContainSubstring("one of For() or Named() must be called")))
124 Expect(instance).To(BeNil())
125 })
126
127 It("should return an error when using Owns without For", func() {
128 By("creating a controller manager")
129 m, err := manager.New(cfg, manager.Options{})
130 Expect(err).NotTo(HaveOccurred())
131
132 instance, err := ControllerManagedBy(m).
133 Named("my_controller").
134 Owns(&appsv1.ReplicaSet{}).
135 Build(noop)
136 Expect(err).To(MatchError(ContainSubstring("Owns() can only be used together with For()")))
137 Expect(instance).To(BeNil())
138
139 })
140
141 It("should return an error when there are no watches", func() {
142 By("creating a controller manager")
143 m, err := manager.New(cfg, manager.Options{})
144 Expect(err).NotTo(HaveOccurred())
145
146 instance, err := ControllerManagedBy(m).
147 Named("my_controller").
148 Build(noop)
149 Expect(err).To(MatchError(ContainSubstring("there are no watches configured, controller will never get triggered. Use For(), Owns(), Watches() or WatchesRawSource() to set them up")))
150 Expect(instance).To(BeNil())
151 })
152
153 It("should allow creating a controllerw without calling For", func() {
154 By("creating a controller manager")
155 m, err := manager.New(cfg, manager.Options{})
156 Expect(err).NotTo(HaveOccurred())
157
158 instance, err := ControllerManagedBy(m).
159 Named("my_controller").
160 Watches(&appsv1.ReplicaSet{}, &handler.EnqueueRequestForObject{}).
161 Build(noop)
162 Expect(err).NotTo(HaveOccurred())
163 Expect(instance).NotTo(BeNil())
164 })
165
166 It("should return an error if there is no GVK for an object, and thus we can't default the controller name", func() {
167 By("creating a controller manager")
168 m, err := manager.New(cfg, manager.Options{})
169 Expect(err).NotTo(HaveOccurred())
170
171 By("creating a controller with a bad For type")
172 instance, err := ControllerManagedBy(m).
173 For(&fakeType{}).
174 Owns(&appsv1.ReplicaSet{}).
175 Build(noop)
176 Expect(err).To(MatchError(ContainSubstring("no kind is registered for the type builder.fakeType")))
177 Expect(instance).To(BeNil())
178
179
180
181
182 })
183
184 It("should return an error if it cannot create the controller", func() {
185 newController = func(name string, mgr manager.Manager, options controller.Options) (
186 controller.Controller, error) {
187 return nil, fmt.Errorf("expected error")
188 }
189
190 By("creating a controller manager")
191 m, err := manager.New(cfg, manager.Options{})
192 Expect(err).NotTo(HaveOccurred())
193
194 instance, err := ControllerManagedBy(m).
195 For(&appsv1.ReplicaSet{}).
196 Owns(&appsv1.ReplicaSet{}).
197 Build(noop)
198 Expect(err).To(HaveOccurred())
199 Expect(err.Error()).To(ContainSubstring("expected error"))
200 Expect(instance).To(BeNil())
201 })
202
203 It("should override max concurrent reconcilers during creation of controller", func() {
204 const maxConcurrentReconciles = 5
205 newController = func(name string, mgr manager.Manager, options controller.Options) (
206 controller.Controller, error) {
207 if options.MaxConcurrentReconciles == maxConcurrentReconciles {
208 return controller.New(name, mgr, options)
209 }
210 return nil, fmt.Errorf("max concurrent reconcilers expected %d but found %d", maxConcurrentReconciles, options.MaxConcurrentReconciles)
211 }
212
213 By("creating a controller manager")
214 m, err := manager.New(cfg, manager.Options{})
215 Expect(err).NotTo(HaveOccurred())
216
217 instance, err := ControllerManagedBy(m).
218 For(&appsv1.ReplicaSet{}).
219 Owns(&appsv1.ReplicaSet{}).
220 WithOptions(controller.Options{MaxConcurrentReconciles: maxConcurrentReconciles}).
221 Build(noop)
222 Expect(err).NotTo(HaveOccurred())
223 Expect(instance).NotTo(BeNil())
224 })
225
226 It("should override max concurrent reconcilers during creation of controller, when using", func() {
227 const maxConcurrentReconciles = 10
228 newController = func(name string, mgr manager.Manager, options controller.Options) (
229 controller.Controller, error) {
230 if options.MaxConcurrentReconciles == maxConcurrentReconciles {
231 return controller.New(name, mgr, options)
232 }
233 return nil, fmt.Errorf("max concurrent reconcilers expected %d but found %d", maxConcurrentReconciles, options.MaxConcurrentReconciles)
234 }
235
236 By("creating a controller manager")
237 m, err := manager.New(cfg, manager.Options{
238 Controller: config.Controller{
239 GroupKindConcurrency: map[string]int{
240 "ReplicaSet.apps": maxConcurrentReconciles,
241 },
242 },
243 })
244 Expect(err).NotTo(HaveOccurred())
245
246 instance, err := ControllerManagedBy(m).
247 For(&appsv1.ReplicaSet{}).
248 Owns(&appsv1.ReplicaSet{}).
249 Build(noop)
250 Expect(err).NotTo(HaveOccurred())
251 Expect(instance).NotTo(BeNil())
252 })
253
254 It("should override rate limiter during creation of controller", func() {
255 rateLimiter := workqueue.DefaultItemBasedRateLimiter()
256 newController = func(name string, mgr manager.Manager, options controller.Options) (controller.Controller, error) {
257 if options.RateLimiter == rateLimiter {
258 return controller.New(name, mgr, options)
259 }
260 return nil, fmt.Errorf("rate limiter expected %T but found %T", rateLimiter, options.RateLimiter)
261 }
262
263 By("creating a controller manager")
264 m, err := manager.New(cfg, manager.Options{})
265 Expect(err).NotTo(HaveOccurred())
266
267 instance, err := ControllerManagedBy(m).
268 For(&appsv1.ReplicaSet{}).
269 Owns(&appsv1.ReplicaSet{}).
270 WithOptions(controller.Options{RateLimiter: rateLimiter}).
271 Build(noop)
272 Expect(err).NotTo(HaveOccurred())
273 Expect(instance).NotTo(BeNil())
274 })
275
276 It("should override logger during creation of controller", func() {
277
278 logger := &testLogger{}
279 newController = func(name string, mgr manager.Manager, options controller.Options) (controller.Controller, error) {
280 if options.LogConstructor(nil).GetSink() == logger {
281 return controller.New(name, mgr, options)
282 }
283 return nil, fmt.Errorf("logger expected %T but found %T", logger, options.LogConstructor)
284 }
285
286 By("creating a controller manager")
287 m, err := manager.New(cfg, manager.Options{})
288 Expect(err).NotTo(HaveOccurred())
289
290 instance, err := ControllerManagedBy(m).
291 For(&appsv1.ReplicaSet{}).
292 Owns(&appsv1.ReplicaSet{}).
293 WithLogConstructor(func(request *reconcile.Request) logr.Logger {
294 return logr.New(logger)
295 }).
296 Build(noop)
297 Expect(err).NotTo(HaveOccurred())
298 Expect(instance).NotTo(BeNil())
299 })
300
301 It("should not allow multiple reconcilers during creation of controller", func() {
302 newController = func(name string, mgr manager.Manager, options controller.Options) (controller.Controller, error) {
303 if options.Reconciler != (typedNoop{}) {
304 return nil, fmt.Errorf("Custom reconciler expected %T but found %T", typedNoop{}, options.Reconciler)
305 }
306 return controller.New(name, mgr, options)
307 }
308
309 By("creating a controller manager")
310 m, err := manager.New(cfg, manager.Options{})
311 Expect(err).NotTo(HaveOccurred())
312
313 instance, err := ControllerManagedBy(m).
314 For(&appsv1.ReplicaSet{}).
315 Owns(&appsv1.ReplicaSet{}).
316 WithOptions(controller.Options{Reconciler: typedNoop{}}).
317 Build(noop)
318 Expect(err).To(HaveOccurred())
319 Expect(instance).To(BeNil())
320 })
321
322 It("should allow multiple controllers for the same kind", func() {
323 By("creating a controller manager")
324 m, err := manager.New(cfg, manager.Options{})
325 Expect(err).NotTo(HaveOccurred())
326
327 By("registering the type in the Scheme")
328 builder := scheme.Builder{GroupVersion: testDefaultValidatorGVK.GroupVersion()}
329 builder.Register(&TestDefaultValidator{}, &TestDefaultValidatorList{})
330 err = builder.AddToScheme(m.GetScheme())
331 Expect(err).NotTo(HaveOccurred())
332
333 By("creating the 1st controller")
334 ctrl1, err := ControllerManagedBy(m).
335 For(&TestDefaultValidator{}).
336 Owns(&appsv1.ReplicaSet{}).
337 Build(noop)
338 Expect(err).NotTo(HaveOccurred())
339 Expect(ctrl1).NotTo(BeNil())
340
341 By("creating the 2nd controller")
342 ctrl2, err := ControllerManagedBy(m).
343 For(&TestDefaultValidator{}).
344 Owns(&appsv1.ReplicaSet{}).
345 Build(noop)
346 Expect(err).NotTo(HaveOccurred())
347 Expect(ctrl2).NotTo(BeNil())
348 })
349 })
350
351 Describe("Start with ControllerManagedBy", func() {
352 It("should Reconcile Owns objects", func() {
353 m, err := manager.New(cfg, manager.Options{})
354 Expect(err).NotTo(HaveOccurred())
355
356 bldr := ControllerManagedBy(m).
357 For(&appsv1.Deployment{}).
358 Owns(&appsv1.ReplicaSet{})
359
360 ctx, cancel := context.WithCancel(context.Background())
361 defer cancel()
362 doReconcileTest(ctx, "3", m, false, bldr)
363 })
364
365 It("should Reconcile Owns objects for every owner", func() {
366 m, err := manager.New(cfg, manager.Options{})
367 Expect(err).NotTo(HaveOccurred())
368
369 bldr := ControllerManagedBy(m).
370 For(&appsv1.Deployment{}).
371 Owns(&appsv1.ReplicaSet{}, MatchEveryOwner)
372
373 ctx, cancel := context.WithCancel(context.Background())
374 defer cancel()
375 doReconcileTest(ctx, "12", m, false, bldr)
376 })
377
378 It("should Reconcile Watches objects", func() {
379 m, err := manager.New(cfg, manager.Options{})
380 Expect(err).NotTo(HaveOccurred())
381
382 bldr := ControllerManagedBy(m).
383 For(&appsv1.Deployment{}).
384 Watches(
385 &appsv1.ReplicaSet{},
386 handler.EnqueueRequestForOwner(m.GetScheme(), m.GetRESTMapper(), &appsv1.Deployment{}, handler.OnlyControllerOwner()),
387 )
388
389 ctx, cancel := context.WithCancel(context.Background())
390 defer cancel()
391 doReconcileTest(ctx, "4", m, true, bldr)
392 })
393
394 It("should Reconcile without For", func() {
395 m, err := manager.New(cfg, manager.Options{})
396 Expect(err).NotTo(HaveOccurred())
397
398 bldr := ControllerManagedBy(m).
399 Named("Deployment").
400 Watches(
401 &appsv1.Deployment{}, &handler.EnqueueRequestForObject{}).
402 Watches(
403 &appsv1.ReplicaSet{},
404 handler.EnqueueRequestForOwner(m.GetScheme(), m.GetRESTMapper(), &appsv1.Deployment{}, handler.OnlyControllerOwner()),
405 )
406
407 ctx, cancel := context.WithCancel(context.Background())
408 defer cancel()
409 doReconcileTest(ctx, "9", m, true, bldr)
410 })
411 })
412
413 Describe("Set custom predicates", func() {
414 It("should execute registered predicates only for assigned kind", func() {
415 m, err := manager.New(cfg, manager.Options{})
416 Expect(err).NotTo(HaveOccurred())
417
418 var (
419 deployPrctExecuted = false
420 replicaSetPrctExecuted = false
421 allPrctExecuted = int64(0)
422 )
423
424 deployPrct := predicate.Funcs{
425 CreateFunc: func(e event.CreateEvent) bool {
426 defer GinkgoRecover()
427
428 Expect(e.Object).To(BeAssignableToTypeOf(&appsv1.Deployment{}))
429 deployPrctExecuted = true
430 return true
431 },
432 }
433
434 replicaSetPrct := predicate.Funcs{
435 CreateFunc: func(e event.CreateEvent) bool {
436 defer GinkgoRecover()
437
438 Expect(e.Object).To(BeAssignableToTypeOf(&appsv1.ReplicaSet{}))
439 replicaSetPrctExecuted = true
440 return true
441 },
442 }
443
444 allPrct := predicate.Funcs{
445 CreateFunc: func(e event.CreateEvent) bool {
446 defer GinkgoRecover()
447
448 Expect(e.Object).Should(Or(
449 BeAssignableToTypeOf(&appsv1.Deployment{}),
450 BeAssignableToTypeOf(&appsv1.ReplicaSet{}),
451 ))
452
453 atomic.AddInt64(&allPrctExecuted, 1)
454 return true
455 },
456 }
457
458 bldr := ControllerManagedBy(m).
459 For(&appsv1.Deployment{}, WithPredicates(deployPrct)).
460 Owns(&appsv1.ReplicaSet{}, WithPredicates(replicaSetPrct)).
461 WithEventFilter(allPrct)
462
463 ctx, cancel := context.WithCancel(context.Background())
464 defer cancel()
465 doReconcileTest(ctx, "5", m, true, bldr)
466
467 Expect(deployPrctExecuted).To(BeTrue(), "Deploy predicated should be called at least once")
468 Expect(replicaSetPrctExecuted).To(BeTrue(), "ReplicaSet predicated should be called at least once")
469 Expect(allPrctExecuted).To(BeNumerically(">=", 2), "Global Predicated should be called at least twice")
470 })
471 })
472
473 Describe("watching with projections", func() {
474 var mgr manager.Manager
475 BeforeEach(func() {
476
477
478 var err error
479 mgr, err = manager.New(cfg, manager.Options{NewCache: newNonTypedOnlyCache})
480 Expect(err).NotTo(HaveOccurred())
481 })
482
483 It("should support multiple controllers watching the same metadata kind", func() {
484 bldr1 := ControllerManagedBy(mgr).For(&appsv1.Deployment{}, OnlyMetadata)
485 bldr2 := ControllerManagedBy(mgr).For(&appsv1.Deployment{}, OnlyMetadata)
486
487 ctx, cancel := context.WithCancel(context.Background())
488 defer cancel()
489
490 doReconcileTest(ctx, "6", mgr, true, bldr1, bldr2)
491 })
492
493 It("should support watching For, Owns, and Watch as metadata", func() {
494 statefulSetMaps := make(chan *metav1.PartialObjectMetadata)
495
496 bldr := ControllerManagedBy(mgr).
497 For(&appsv1.Deployment{}, OnlyMetadata).
498 Owns(&appsv1.ReplicaSet{}, OnlyMetadata).
499 Watches(&appsv1.StatefulSet{},
500 handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []reconcile.Request {
501 defer GinkgoRecover()
502
503 ometa := o.(*metav1.PartialObjectMetadata)
504 statefulSetMaps <- ometa
505
506
507 Expect(o.GetObjectKind().GroupVersionKind()).To(Equal(schema.GroupVersionKind{
508 Group: "apps",
509 Version: "v1",
510 Kind: "StatefulSet",
511 }))
512 return nil
513 }),
514 OnlyMetadata)
515
516 ctx, cancel := context.WithCancel(context.Background())
517 defer cancel()
518 doReconcileTest(ctx, "8", mgr, true, bldr)
519
520 By("Creating a new stateful set")
521 set := &appsv1.StatefulSet{
522 ObjectMeta: metav1.ObjectMeta{
523 Namespace: "default",
524 Name: "test1",
525 Labels: map[string]string{
526 "foo": "bar",
527 },
528 },
529 Spec: appsv1.StatefulSetSpec{
530 Selector: &metav1.LabelSelector{
531 MatchLabels: map[string]string{"foo": "bar"},
532 },
533 Template: corev1.PodTemplateSpec{
534 ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
535 Spec: corev1.PodSpec{
536 Containers: []corev1.Container{
537 {
538 Name: "nginx",
539 Image: "nginx",
540 },
541 },
542 },
543 },
544 },
545 }
546 err := mgr.GetClient().Create(context.TODO(), set)
547 Expect(err).NotTo(HaveOccurred())
548
549 By("Checking that the mapping function has been called")
550 Eventually(func() bool {
551 metaSet := <-statefulSetMaps
552 Expect(metaSet.Name).To(Equal(set.Name))
553 Expect(metaSet.Namespace).To(Equal(set.Namespace))
554 Expect(metaSet.Labels).To(Equal(set.Labels))
555 return true
556 }).Should(BeTrue())
557 })
558 })
559 })
560
561
562
563 func newNonTypedOnlyCache(config *rest.Config, opts cache.Options) (cache.Cache, error) {
564 normalCache, err := cache.New(config, opts)
565 if err != nil {
566 return nil, err
567 }
568 return &nonTypedOnlyCache{
569 Cache: normalCache,
570 }, nil
571 }
572
573
574
575 type nonTypedOnlyCache struct {
576 cache.Cache
577 }
578
579 func (c *nonTypedOnlyCache) GetInformer(ctx context.Context, obj client.Object, opts ...cache.InformerGetOption) (cache.Informer, error) {
580 switch obj.(type) {
581 case (*metav1.PartialObjectMetadata):
582 return c.Cache.GetInformer(ctx, obj, opts...)
583 default:
584 return nil, fmt.Errorf("did not want to provide an informer for normal type %T", obj)
585 }
586 }
587 func (c *nonTypedOnlyCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind, opts ...cache.InformerGetOption) (cache.Informer, error) {
588 return nil, fmt.Errorf("don't try to sidestep the restriction on informer types by calling GetInformerForKind")
589 }
590
591
592
593 func doReconcileTest(ctx context.Context, nameSuffix string, mgr manager.Manager, complete bool, blders ...*Builder) {
594 deployName := "deploy-name-" + nameSuffix
595 rsName := "rs-name-" + nameSuffix
596
597 By("Creating the application")
598 ch := make(chan reconcile.Request)
599 fn := reconcile.Func(func(_ context.Context, req reconcile.Request) (reconcile.Result, error) {
600 defer GinkgoRecover()
601 if !strings.HasSuffix(req.Name, nameSuffix) {
602
603 return reconcile.Result{}, nil
604 }
605 ch <- req
606 return reconcile.Result{}, nil
607 })
608
609 for _, blder := range blders {
610 if complete {
611 err := blder.Complete(fn)
612 Expect(err).NotTo(HaveOccurred())
613 } else {
614 var err error
615 var c controller.Controller
616 c, err = blder.Build(fn)
617 Expect(err).NotTo(HaveOccurred())
618 Expect(c).NotTo(BeNil())
619 }
620 }
621
622 By("Starting the application")
623 go func() {
624 defer GinkgoRecover()
625 Expect(mgr.Start(ctx)).NotTo(HaveOccurred())
626 }()
627
628 By("Creating a Deployment")
629
630 dep := &appsv1.Deployment{
631 ObjectMeta: metav1.ObjectMeta{
632 Namespace: "default",
633 Name: deployName,
634 },
635 Spec: appsv1.DeploymentSpec{
636 Selector: &metav1.LabelSelector{
637 MatchLabels: map[string]string{"foo": "bar"},
638 },
639 Template: corev1.PodTemplateSpec{
640 ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}},
641 Spec: corev1.PodSpec{
642 Containers: []corev1.Container{
643 {
644 Name: "nginx",
645 Image: "nginx",
646 },
647 },
648 },
649 },
650 },
651 }
652 err := mgr.GetClient().Create(ctx, dep)
653 Expect(err).NotTo(HaveOccurred())
654
655 By("Waiting for the Deployment Reconcile")
656 Eventually(ch).Should(Receive(Equal(reconcile.Request{
657 NamespacedName: types.NamespacedName{Namespace: "default", Name: deployName}})))
658
659 By("Creating a ReplicaSet")
660
661 rs := &appsv1.ReplicaSet{
662 ObjectMeta: metav1.ObjectMeta{
663 Namespace: "default",
664 Name: rsName,
665 Labels: dep.Spec.Selector.MatchLabels,
666 OwnerReferences: []metav1.OwnerReference{
667 {
668 Name: deployName,
669 Kind: "Deployment",
670 APIVersion: "apps/v1",
671 Controller: ptr.To(true),
672 UID: dep.UID,
673 },
674 },
675 },
676 Spec: appsv1.ReplicaSetSpec{
677 Selector: dep.Spec.Selector,
678 Template: dep.Spec.Template,
679 },
680 }
681 err = mgr.GetClient().Create(ctx, rs)
682 Expect(err).NotTo(HaveOccurred())
683
684 By("Waiting for the ReplicaSet Reconcile")
685 Eventually(ch).Should(Receive(Equal(reconcile.Request{
686 NamespacedName: types.NamespacedName{Namespace: "default", Name: deployName}})))
687 }
688
689 var _ runtime.Object = &fakeType{}
690
691 type fakeType struct {
692 metav1.TypeMeta
693 metav1.ObjectMeta
694 }
695
696 func (*fakeType) GetObjectKind() schema.ObjectKind { return nil }
697 func (*fakeType) DeepCopyObject() runtime.Object { return nil }
698
View as plain text