1
16
17 package deployment
18
19 import (
20 "context"
21 "fmt"
22 "strconv"
23 "testing"
24
25 apps "k8s.io/api/apps/v1"
26 v1 "k8s.io/api/core/v1"
27 extensions "k8s.io/api/extensions/v1beta1"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/apimachinery/pkg/runtime"
30 "k8s.io/apimachinery/pkg/runtime/schema"
31 "k8s.io/apimachinery/pkg/util/intstr"
32 "k8s.io/apimachinery/pkg/util/uuid"
33 "k8s.io/client-go/informers"
34 "k8s.io/client-go/kubernetes/fake"
35 core "k8s.io/client-go/testing"
36 "k8s.io/client-go/tools/record"
37 "k8s.io/klog/v2"
38 "k8s.io/klog/v2/ktesting"
39 _ "k8s.io/kubernetes/pkg/apis/apps/install"
40 _ "k8s.io/kubernetes/pkg/apis/authentication/install"
41 _ "k8s.io/kubernetes/pkg/apis/authorization/install"
42 _ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
43 _ "k8s.io/kubernetes/pkg/apis/batch/install"
44 _ "k8s.io/kubernetes/pkg/apis/certificates/install"
45 _ "k8s.io/kubernetes/pkg/apis/core/install"
46 _ "k8s.io/kubernetes/pkg/apis/policy/install"
47 _ "k8s.io/kubernetes/pkg/apis/rbac/install"
48 _ "k8s.io/kubernetes/pkg/apis/storage/install"
49 "k8s.io/kubernetes/pkg/controller"
50 "k8s.io/kubernetes/pkg/controller/deployment/util"
51 "k8s.io/kubernetes/pkg/controller/testutil"
52 "k8s.io/utils/ptr"
53 )
54
55 var (
56 alwaysReady = func() bool { return true }
57 noTimestamp = metav1.Time{}
58 )
59
60 func rs(name string, replicas int32, selector map[string]string, timestamp metav1.Time) *apps.ReplicaSet {
61 return &apps.ReplicaSet{
62 ObjectMeta: metav1.ObjectMeta{
63 Name: name,
64 CreationTimestamp: timestamp,
65 Namespace: metav1.NamespaceDefault,
66 },
67 Spec: apps.ReplicaSetSpec{
68 Replicas: ptr.To(replicas),
69 Selector: &metav1.LabelSelector{MatchLabels: selector},
70 Template: v1.PodTemplateSpec{},
71 },
72 }
73 }
74
75 func newRSWithStatus(name string, specReplicas, statusReplicas int32, selector map[string]string) *apps.ReplicaSet {
76 rs := rs(name, specReplicas, selector, noTimestamp)
77 rs.Status = apps.ReplicaSetStatus{
78 Replicas: statusReplicas,
79 }
80 return rs
81 }
82
83 func newDeployment(name string, replicas int32, revisionHistoryLimit *int32, maxSurge, maxUnavailable *intstr.IntOrString, selector map[string]string) *apps.Deployment {
84 d := apps.Deployment{
85 TypeMeta: metav1.TypeMeta{APIVersion: "apps/v1", Kind: "Deployment"},
86 ObjectMeta: metav1.ObjectMeta{
87 UID: uuid.NewUUID(),
88 Name: name,
89 Namespace: metav1.NamespaceDefault,
90 Annotations: make(map[string]string),
91 },
92 Spec: apps.DeploymentSpec{
93 Strategy: apps.DeploymentStrategy{
94 Type: apps.RollingUpdateDeploymentStrategyType,
95 RollingUpdate: &apps.RollingUpdateDeployment{
96 MaxUnavailable: ptr.To(intstr.FromInt32(0)),
97 MaxSurge: ptr.To(intstr.FromInt32(0)),
98 },
99 },
100 Replicas: ptr.To(replicas),
101 Selector: &metav1.LabelSelector{MatchLabels: selector},
102 Template: v1.PodTemplateSpec{
103 ObjectMeta: metav1.ObjectMeta{
104 Labels: selector,
105 },
106 Spec: v1.PodSpec{
107 Containers: []v1.Container{
108 {
109 Image: "foo/bar",
110 },
111 },
112 },
113 },
114 RevisionHistoryLimit: revisionHistoryLimit,
115 },
116 }
117 if maxSurge != nil {
118 d.Spec.Strategy.RollingUpdate.MaxSurge = maxSurge
119 }
120 if maxUnavailable != nil {
121 d.Spec.Strategy.RollingUpdate.MaxUnavailable = maxUnavailable
122 }
123 return &d
124 }
125
126 func newReplicaSet(d *apps.Deployment, name string, replicas int32) *apps.ReplicaSet {
127 return &apps.ReplicaSet{
128 TypeMeta: metav1.TypeMeta{Kind: "ReplicaSet"},
129 ObjectMeta: metav1.ObjectMeta{
130 Name: name,
131 UID: uuid.NewUUID(),
132 Namespace: metav1.NamespaceDefault,
133 Labels: d.Spec.Selector.MatchLabels,
134 OwnerReferences: []metav1.OwnerReference{*metav1.NewControllerRef(d, controllerKind)},
135 },
136 Spec: apps.ReplicaSetSpec{
137 Selector: d.Spec.Selector,
138 Replicas: ptr.To(replicas),
139 Template: d.Spec.Template,
140 },
141 }
142 }
143
144 type fixture struct {
145 t testing.TB
146
147 client *fake.Clientset
148
149 dLister []*apps.Deployment
150 rsLister []*apps.ReplicaSet
151 podLister []*v1.Pod
152
153
154
155 actions []core.Action
156 objects []runtime.Object
157 }
158
159 func (f *fixture) expectGetDeploymentAction(d *apps.Deployment) {
160 action := core.NewGetAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d.Name)
161 f.actions = append(f.actions, action)
162 }
163
164 func (f *fixture) expectUpdateDeploymentStatusAction(d *apps.Deployment) {
165 action := core.NewUpdateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d)
166 action.Subresource = "status"
167 f.actions = append(f.actions, action)
168 }
169
170 func (f *fixture) expectUpdateDeploymentAction(d *apps.Deployment) {
171 action := core.NewUpdateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d)
172 f.actions = append(f.actions, action)
173 }
174
175 func (f *fixture) expectCreateRSAction(rs *apps.ReplicaSet) {
176 f.actions = append(f.actions, core.NewCreateAction(schema.GroupVersionResource{Resource: "replicasets"}, rs.Namespace, rs))
177 }
178
179 func newFixture(t testing.TB) *fixture {
180 f := &fixture{}
181 f.t = t
182 f.objects = []runtime.Object{}
183 return f
184 }
185
186 func (f *fixture) newController(ctx context.Context) (*DeploymentController, informers.SharedInformerFactory, error) {
187 f.client = fake.NewSimpleClientset(f.objects...)
188 informers := informers.NewSharedInformerFactory(f.client, controller.NoResyncPeriodFunc())
189 c, err := NewDeploymentController(ctx, informers.Apps().V1().Deployments(), informers.Apps().V1().ReplicaSets(), informers.Core().V1().Pods(), f.client)
190 if err != nil {
191 return nil, nil, err
192 }
193 c.eventRecorder = &record.FakeRecorder{}
194 c.dListerSynced = alwaysReady
195 c.rsListerSynced = alwaysReady
196 c.podListerSynced = alwaysReady
197 for _, d := range f.dLister {
198 informers.Apps().V1().Deployments().Informer().GetIndexer().Add(d)
199 }
200 for _, rs := range f.rsLister {
201 informers.Apps().V1().ReplicaSets().Informer().GetIndexer().Add(rs)
202 }
203 for _, pod := range f.podLister {
204 informers.Core().V1().Pods().Informer().GetIndexer().Add(pod)
205 }
206 return c, informers, nil
207 }
208
209 func (f *fixture) runExpectError(ctx context.Context, deploymentName string, startInformers bool) {
210 f.run_(ctx, deploymentName, startInformers, true)
211 }
212
213 func (f *fixture) run(ctx context.Context, deploymentName string) {
214 f.run_(ctx, deploymentName, true, false)
215 }
216
217 func (f *fixture) run_(ctx context.Context, deploymentName string, startInformers bool, expectError bool) {
218 c, informers, err := f.newController(ctx)
219 if err != nil {
220 f.t.Fatalf("error creating Deployment controller: %v", err)
221 }
222 if startInformers {
223 stopCh := make(chan struct{})
224 defer close(stopCh)
225 informers.Start(stopCh)
226 }
227
228 err = c.syncDeployment(ctx, deploymentName)
229 if !expectError && err != nil {
230 f.t.Errorf("error syncing deployment: %v", err)
231 } else if expectError && err == nil {
232 f.t.Error("expected error syncing deployment, got nil")
233 }
234
235 actions := filterInformerActions(f.client.Actions())
236 for i, action := range actions {
237 if len(f.actions) < i+1 {
238 f.t.Errorf("%d unexpected actions: %+v", len(actions)-len(f.actions), actions[i:])
239 break
240 }
241
242 expectedAction := f.actions[i]
243 if !(expectedAction.Matches(action.GetVerb(), action.GetResource().Resource) && action.GetSubresource() == expectedAction.GetSubresource()) {
244 f.t.Errorf("Expected\n\t%#v\ngot\n\t%#v", expectedAction, action)
245 continue
246 }
247 }
248
249 if len(f.actions) > len(actions) {
250 f.t.Errorf("%d additional expected actions:%+v", len(f.actions)-len(actions), f.actions[len(actions):])
251 }
252 }
253
254 func filterInformerActions(actions []core.Action) []core.Action {
255 ret := []core.Action{}
256 for _, action := range actions {
257 if len(action.GetNamespace()) == 0 &&
258 (action.Matches("list", "pods") ||
259 action.Matches("list", "deployments") ||
260 action.Matches("list", "replicasets") ||
261 action.Matches("watch", "pods") ||
262 action.Matches("watch", "deployments") ||
263 action.Matches("watch", "replicasets")) {
264 continue
265 }
266 ret = append(ret, action)
267 }
268
269 return ret
270 }
271
272 func TestSyncDeploymentCreatesReplicaSet(t *testing.T) {
273 _, ctx := ktesting.NewTestContext(t)
274
275 f := newFixture(t)
276
277 d := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
278 f.dLister = append(f.dLister, d)
279 f.objects = append(f.objects, d)
280
281 rs := newReplicaSet(d, "deploymentrs-4186632231", 1)
282
283 f.expectCreateRSAction(rs)
284 f.expectUpdateDeploymentStatusAction(d)
285 f.expectUpdateDeploymentStatusAction(d)
286
287 f.run(ctx, testutil.GetKey(d, t))
288 }
289
290 func TestSyncDeploymentDontDoAnythingDuringDeletion(t *testing.T) {
291 _, ctx := ktesting.NewTestContext(t)
292
293 f := newFixture(t)
294
295 d := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
296 now := metav1.Now()
297 d.DeletionTimestamp = &now
298 f.dLister = append(f.dLister, d)
299 f.objects = append(f.objects, d)
300
301 f.expectUpdateDeploymentStatusAction(d)
302 f.run(ctx, testutil.GetKey(d, t))
303 }
304
305 func TestSyncDeploymentDeletionRace(t *testing.T) {
306 _, ctx := ktesting.NewTestContext(t)
307
308 f := newFixture(t)
309
310 d := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
311 d2 := *d
312
313 f.dLister = append(f.dLister, d)
314
315 now := metav1.Now()
316 d2.DeletionTimestamp = &now
317 f.objects = append(f.objects, &d2)
318
319
320 rs := newReplicaSet(d, "rs1", 1)
321 rs.OwnerReferences = nil
322 f.objects = append(f.objects, rs)
323 f.rsLister = append(f.rsLister, rs)
324
325
326 f.expectGetDeploymentAction(d)
327
328
329 f.runExpectError(ctx, testutil.GetKey(d, t), false)
330 }
331
332
333 func TestDontSyncDeploymentsWithEmptyPodSelector(t *testing.T) {
334 _, ctx := ktesting.NewTestContext(t)
335 ctx, cancel := context.WithCancel(ctx)
336 defer cancel()
337
338 f := newFixture(t)
339
340 d := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
341 d.Spec.Selector = &metav1.LabelSelector{}
342 f.dLister = append(f.dLister, d)
343 f.objects = append(f.objects, d)
344
345
346
347 f.run(ctx, testutil.GetKey(d, t))
348 }
349
350 func TestReentrantRollback(t *testing.T) {
351 _, ctx := ktesting.NewTestContext(t)
352
353 f := newFixture(t)
354
355 d := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
356 d.Annotations = map[string]string{util.RevisionAnnotation: "2"}
357 setRollbackTo(d, &extensions.RollbackConfig{Revision: 0})
358 f.dLister = append(f.dLister, d)
359
360 rs1 := newReplicaSet(d, "deploymentrs-old", 0)
361 rs1.Annotations = map[string]string{util.RevisionAnnotation: "1"}
362 one := int64(1)
363 rs1.Spec.Template.Spec.TerminationGracePeriodSeconds = &one
364 rs1.Spec.Selector.MatchLabels[apps.DefaultDeploymentUniqueLabelKey] = "hash"
365
366 rs2 := newReplicaSet(d, "deploymentrs-new", 1)
367 rs2.Annotations = map[string]string{util.RevisionAnnotation: "2"}
368 rs2.Spec.Selector.MatchLabels[apps.DefaultDeploymentUniqueLabelKey] = "hash"
369
370 f.rsLister = append(f.rsLister, rs1, rs2)
371 f.objects = append(f.objects, d, rs1, rs2)
372
373
374 f.expectUpdateDeploymentAction(d)
375
376 f.run(ctx, testutil.GetKey(d, t))
377 }
378
379
380
381
382 func TestPodDeletionEnqueuesRecreateDeployment(t *testing.T) {
383 logger, ctx := ktesting.NewTestContext(t)
384
385 f := newFixture(t)
386
387 foo := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
388 foo.Spec.Strategy.Type = apps.RecreateDeploymentStrategyType
389 rs := newReplicaSet(foo, "foo-1", 1)
390 pod := generatePodFromRS(rs)
391
392 f.dLister = append(f.dLister, foo)
393 f.rsLister = append(f.rsLister, rs)
394 f.objects = append(f.objects, foo, rs)
395
396 c, _, err := f.newController(ctx)
397 if err != nil {
398 t.Fatalf("error creating Deployment controller: %v", err)
399 }
400 enqueued := false
401 c.enqueueDeployment = func(d *apps.Deployment) {
402 if d.Name == "foo" {
403 enqueued = true
404 }
405 }
406
407 c.deletePod(logger, pod)
408
409 if !enqueued {
410 t.Errorf("expected deployment %q to be queued after pod deletion", foo.Name)
411 }
412 }
413
414
415
416
417 func TestPodDeletionDoesntEnqueueRecreateDeployment(t *testing.T) {
418 logger, ctx := ktesting.NewTestContext(t)
419
420 f := newFixture(t)
421
422 foo := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
423 foo.Spec.Strategy.Type = apps.RecreateDeploymentStrategyType
424 rs1 := newReplicaSet(foo, "foo-1", 1)
425 rs2 := newReplicaSet(foo, "foo-1", 1)
426 pod1 := generatePodFromRS(rs1)
427 pod2 := generatePodFromRS(rs2)
428
429 f.dLister = append(f.dLister, foo)
430
431
432 f.podLister = append(f.podLister, pod1, pod2)
433
434 c, _, err := f.newController(ctx)
435 if err != nil {
436 t.Fatalf("error creating Deployment controller: %v", err)
437 }
438 enqueued := false
439 c.enqueueDeployment = func(d *apps.Deployment) {
440 if d.Name == "foo" {
441 enqueued = true
442 }
443 }
444
445 c.deletePod(logger, pod1)
446
447 if enqueued {
448 t.Errorf("expected deployment %q not to be queued after pod deletion", foo.Name)
449 }
450 }
451
452
453
454
455
456 func TestPodDeletionPartialReplicaSetOwnershipEnqueueRecreateDeployment(t *testing.T) {
457 logger, ctx := ktesting.NewTestContext(t)
458
459 f := newFixture(t)
460
461 foo := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
462 foo.Spec.Strategy.Type = apps.RecreateDeploymentStrategyType
463 rs1 := newReplicaSet(foo, "foo-1", 1)
464 rs2 := newReplicaSet(foo, "foo-2", 2)
465 rs2.OwnerReferences = nil
466 pod := generatePodFromRS(rs1)
467
468 f.dLister = append(f.dLister, foo)
469 f.rsLister = append(f.rsLister, rs1, rs2)
470 f.objects = append(f.objects, foo, rs1, rs2)
471
472 c, _, err := f.newController(ctx)
473 if err != nil {
474 t.Fatalf("error creating Deployment controller: %v", err)
475 }
476 enqueued := false
477 c.enqueueDeployment = func(d *apps.Deployment) {
478 if d.Name == "foo" {
479 enqueued = true
480 }
481 }
482
483 c.deletePod(logger, pod)
484
485 if !enqueued {
486 t.Errorf("expected deployment %q to be queued after pod deletion", foo.Name)
487 }
488 }
489
490
491
492
493
494 func TestPodDeletionPartialReplicaSetOwnershipDoesntEnqueueRecreateDeployment(t *testing.T) {
495 logger, ctx := ktesting.NewTestContext(t)
496
497 f := newFixture(t)
498
499 foo := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
500 foo.Spec.Strategy.Type = apps.RecreateDeploymentStrategyType
501 rs1 := newReplicaSet(foo, "foo-1", 1)
502 rs2 := newReplicaSet(foo, "foo-2", 2)
503 rs2.OwnerReferences = nil
504 pod := generatePodFromRS(rs1)
505
506 f.dLister = append(f.dLister, foo)
507 f.rsLister = append(f.rsLister, rs1, rs2)
508 f.objects = append(f.objects, foo, rs1, rs2)
509
510
511 f.podLister = append(f.podLister, pod)
512
513 c, _, err := f.newController(ctx)
514 if err != nil {
515 t.Fatalf("error creating Deployment controller: %v", err)
516 }
517 enqueued := false
518 c.enqueueDeployment = func(d *apps.Deployment) {
519 if d.Name == "foo" {
520 enqueued = true
521 }
522 }
523
524 c.deletePod(logger, pod)
525
526 if enqueued {
527 t.Errorf("expected deployment %q not to be queued after pod deletion", foo.Name)
528 }
529 }
530
531 func TestGetReplicaSetsForDeployment(t *testing.T) {
532 _, ctx := ktesting.NewTestContext(t)
533
534 f := newFixture(t)
535
536
537 d1 := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
538 d2 := newDeployment("bar", 1, nil, nil, nil, map[string]string{"foo": "bar"})
539
540
541
542 rs1 := newReplicaSet(d1, "rs1", 1)
543 rs2 := newReplicaSet(d2, "rs2", 1)
544
545 f.dLister = append(f.dLister, d1, d2)
546 f.rsLister = append(f.rsLister, rs1, rs2)
547 f.objects = append(f.objects, d1, d2, rs1, rs2)
548
549
550 c, informers, err := f.newController(ctx)
551 if err != nil {
552 t.Fatalf("error creating Deployment controller: %v", err)
553 }
554 stopCh := make(chan struct{})
555 defer close(stopCh)
556 informers.Start(stopCh)
557
558 rsList, err := c.getReplicaSetsForDeployment(ctx, d1)
559 if err != nil {
560 t.Fatalf("getReplicaSetsForDeployment() error: %v", err)
561 }
562 rsNames := []string{}
563 for _, rs := range rsList {
564 rsNames = append(rsNames, rs.Name)
565 }
566 if len(rsNames) != 1 || rsNames[0] != rs1.Name {
567 t.Errorf("getReplicaSetsForDeployment() = %v, want [%v]", rsNames, rs1.Name)
568 }
569
570 rsList, err = c.getReplicaSetsForDeployment(ctx, d2)
571 if err != nil {
572 t.Fatalf("getReplicaSetsForDeployment() error: %v", err)
573 }
574 rsNames = []string{}
575 for _, rs := range rsList {
576 rsNames = append(rsNames, rs.Name)
577 }
578 if len(rsNames) != 1 || rsNames[0] != rs2.Name {
579 t.Errorf("getReplicaSetsForDeployment() = %v, want [%v]", rsNames, rs2.Name)
580 }
581 }
582
583 func TestGetReplicaSetsForDeploymentAdoptRelease(t *testing.T) {
584 _, ctx := ktesting.NewTestContext(t)
585
586 f := newFixture(t)
587
588 d := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
589
590
591 rsAdopt := newReplicaSet(d, "rsAdopt", 1)
592 rsAdopt.OwnerReferences = nil
593
594 rsRelease := newReplicaSet(d, "rsRelease", 1)
595 rsRelease.Labels = map[string]string{"foo": "notbar"}
596
597 f.dLister = append(f.dLister, d)
598 f.rsLister = append(f.rsLister, rsAdopt, rsRelease)
599 f.objects = append(f.objects, d, rsAdopt, rsRelease)
600
601
602 c, informers, err := f.newController(ctx)
603 if err != nil {
604 t.Fatalf("error creating Deployment controller: %v", err)
605 }
606 stopCh := make(chan struct{})
607 defer close(stopCh)
608 informers.Start(stopCh)
609
610 rsList, err := c.getReplicaSetsForDeployment(ctx, d)
611 if err != nil {
612 t.Fatalf("getReplicaSetsForDeployment() error: %v", err)
613 }
614 rsNames := []string{}
615 for _, rs := range rsList {
616 rsNames = append(rsNames, rs.Name)
617 }
618 if len(rsNames) != 1 || rsNames[0] != rsAdopt.Name {
619 t.Errorf("getReplicaSetsForDeployment() = %v, want [%v]", rsNames, rsAdopt.Name)
620 }
621 }
622
623 func TestGetPodMapForReplicaSets(t *testing.T) {
624 _, ctx := ktesting.NewTestContext(t)
625
626 f := newFixture(t)
627
628 d := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
629
630 rs1 := newReplicaSet(d, "rs1", 1)
631 rs2 := newReplicaSet(d, "rs2", 1)
632
633
634 pod1 := generatePodFromRS(rs1)
635 pod2 := generatePodFromRS(rs2)
636
637 pod3 := generatePodFromRS(rs1)
638 pod3.Name = "pod3"
639 pod3.OwnerReferences = nil
640
641 pod4 := generatePodFromRS(rs1)
642 pod4.Name = "pod4"
643 pod4.Status.Phase = v1.PodFailed
644
645 f.dLister = append(f.dLister, d)
646 f.rsLister = append(f.rsLister, rs1, rs2)
647 f.podLister = append(f.podLister, pod1, pod2, pod3, pod4)
648 f.objects = append(f.objects, d, rs1, rs2, pod1, pod2, pod3, pod4)
649
650
651 c, informers, err := f.newController(ctx)
652 if err != nil {
653 t.Fatalf("error creating Deployment controller: %v", err)
654 }
655 stopCh := make(chan struct{})
656 defer close(stopCh)
657 informers.Start(stopCh)
658
659 podMap, err := c.getPodMapForDeployment(d, f.rsLister)
660 if err != nil {
661 t.Fatalf("getPodMapForDeployment() error: %v", err)
662 }
663 podCount := 0
664 for _, podList := range podMap {
665 podCount += len(podList)
666 }
667 if got, want := podCount, 3; got != want {
668 t.Errorf("podCount = %v, want %v", got, want)
669 }
670
671 if got, want := len(podMap), 2; got != want {
672 t.Errorf("len(podMap) = %v, want %v", got, want)
673 }
674 if got, want := len(podMap[rs1.UID]), 2; got != want {
675 t.Errorf("len(podMap[rs1]) = %v, want %v", got, want)
676 }
677 expect := map[string]struct{}{"rs1-pod": {}, "pod4": {}}
678 for _, pod := range podMap[rs1.UID] {
679 if _, ok := expect[pod.Name]; !ok {
680 t.Errorf("unexpected pod name for rs1: %s", pod.Name)
681 }
682 }
683 if got, want := len(podMap[rs2.UID]), 1; got != want {
684 t.Errorf("len(podMap[rs2]) = %v, want %v", got, want)
685 }
686 if got, want := podMap[rs2.UID][0].Name, "rs2-pod"; got != want {
687 t.Errorf("podMap[rs2] = [%v], want [%v]", got, want)
688 }
689 }
690
691 func TestAddReplicaSet(t *testing.T) {
692 logger, ctx := ktesting.NewTestContext(t)
693
694 f := newFixture(t)
695
696 d1 := newDeployment("d1", 1, nil, nil, nil, map[string]string{"foo": "bar"})
697 d2 := newDeployment("d2", 1, nil, nil, nil, map[string]string{"foo": "bar"})
698
699
700
701 rs1 := newReplicaSet(d1, "rs1", 1)
702 rs2 := newReplicaSet(d2, "rs2", 1)
703
704 f.dLister = append(f.dLister, d1, d2)
705 f.objects = append(f.objects, d1, d2, rs1, rs2)
706
707
708
709 dc, _, err := f.newController(ctx)
710 if err != nil {
711 t.Fatalf("error creating Deployment controller: %v", err)
712 }
713
714 dc.addReplicaSet(klog.FromContext(ctx), rs1)
715 if got, want := dc.queue.Len(), 1; got != want {
716 t.Fatalf("queue.Len() = %v, want %v", got, want)
717 }
718 key, done := dc.queue.Get()
719 if key == nil || done {
720 t.Fatalf("failed to enqueue controller for rs %v", rs1.Name)
721 }
722 expectedKey, _ := controller.KeyFunc(d1)
723 if got, want := key.(string), expectedKey; got != want {
724 t.Errorf("queue.Get() = %v, want %v", got, want)
725 }
726
727 dc.addReplicaSet(logger, rs2)
728 if got, want := dc.queue.Len(), 1; got != want {
729 t.Fatalf("queue.Len() = %v, want %v", got, want)
730 }
731 key, done = dc.queue.Get()
732 if key == nil || done {
733 t.Fatalf("failed to enqueue controller for rs %v", rs2.Name)
734 }
735 expectedKey, _ = controller.KeyFunc(d2)
736 if got, want := key.(string), expectedKey; got != want {
737 t.Errorf("queue.Get() = %v, want %v", got, want)
738 }
739 }
740
741 func TestAddReplicaSetOrphan(t *testing.T) {
742 logger, ctx := ktesting.NewTestContext(t)
743
744 f := newFixture(t)
745
746
747 d1 := newDeployment("d1", 1, nil, nil, nil, map[string]string{"foo": "bar"})
748 d2 := newDeployment("d2", 1, nil, nil, nil, map[string]string{"foo": "bar"})
749 d3 := newDeployment("d3", 1, nil, nil, nil, map[string]string{"foo": "bar"})
750 d3.Spec.Selector.MatchLabels = map[string]string{"foo": "notbar"}
751
752
753 rs := newReplicaSet(d1, "rs1", 1)
754 rs.OwnerReferences = nil
755
756 f.dLister = append(f.dLister, d1, d2, d3)
757 f.objects = append(f.objects, d1, d2, d3)
758
759
760
761 dc, _, err := f.newController(ctx)
762 if err != nil {
763 t.Fatalf("error creating Deployment controller: %v", err)
764 }
765
766 dc.addReplicaSet(logger, rs)
767 if got, want := dc.queue.Len(), 2; got != want {
768 t.Fatalf("queue.Len() = %v, want %v", got, want)
769 }
770 }
771
772 func TestUpdateReplicaSet(t *testing.T) {
773 logger, ctx := ktesting.NewTestContext(t)
774
775 f := newFixture(t)
776
777 d1 := newDeployment("d1", 1, nil, nil, nil, map[string]string{"foo": "bar"})
778 d2 := newDeployment("d2", 1, nil, nil, nil, map[string]string{"foo": "bar"})
779
780
781
782 rs1 := newReplicaSet(d1, "rs1", 1)
783 rs2 := newReplicaSet(d2, "rs2", 1)
784
785 f.dLister = append(f.dLister, d1, d2)
786 f.rsLister = append(f.rsLister, rs1, rs2)
787 f.objects = append(f.objects, d1, d2, rs1, rs2)
788
789
790
791 dc, _, err := f.newController(ctx)
792 if err != nil {
793 t.Fatalf("error creating Deployment controller: %v", err)
794 }
795
796 prev := *rs1
797 next := *rs1
798 bumpResourceVersion(&next)
799 dc.updateReplicaSet(logger, &prev, &next)
800 if got, want := dc.queue.Len(), 1; got != want {
801 t.Fatalf("queue.Len() = %v, want %v", got, want)
802 }
803 key, done := dc.queue.Get()
804 if key == nil || done {
805 t.Fatalf("failed to enqueue controller for rs %v", rs1.Name)
806 }
807 expectedKey, _ := controller.KeyFunc(d1)
808 if got, want := key.(string), expectedKey; got != want {
809 t.Errorf("queue.Get() = %v, want %v", got, want)
810 }
811
812 prev = *rs2
813 next = *rs2
814 bumpResourceVersion(&next)
815 dc.updateReplicaSet(logger, &prev, &next)
816 if got, want := dc.queue.Len(), 1; got != want {
817 t.Fatalf("queue.Len() = %v, want %v", got, want)
818 }
819 key, done = dc.queue.Get()
820 if key == nil || done {
821 t.Fatalf("failed to enqueue controller for rs %v", rs2.Name)
822 }
823 expectedKey, _ = controller.KeyFunc(d2)
824 if got, want := key.(string), expectedKey; got != want {
825 t.Errorf("queue.Get() = %v, want %v", got, want)
826 }
827 }
828
829 func TestUpdateReplicaSetOrphanWithNewLabels(t *testing.T) {
830 logger, ctx := ktesting.NewTestContext(t)
831
832 f := newFixture(t)
833
834 d1 := newDeployment("d1", 1, nil, nil, nil, map[string]string{"foo": "bar"})
835 d2 := newDeployment("d2", 1, nil, nil, nil, map[string]string{"foo": "bar"})
836
837
838 rs := newReplicaSet(d1, "rs1", 1)
839 rs.OwnerReferences = nil
840
841 f.dLister = append(f.dLister, d1, d2)
842 f.rsLister = append(f.rsLister, rs)
843 f.objects = append(f.objects, d1, d2, rs)
844
845
846
847 dc, _, err := f.newController(ctx)
848 if err != nil {
849 t.Fatalf("error creating Deployment controller: %v", err)
850 }
851
852
853 prev := *rs
854 prev.Labels = map[string]string{"foo": "notbar"}
855 next := *rs
856 bumpResourceVersion(&next)
857 dc.updateReplicaSet(logger, &prev, &next)
858 if got, want := dc.queue.Len(), 2; got != want {
859 t.Fatalf("queue.Len() = %v, want %v", got, want)
860 }
861 }
862
863 func TestUpdateReplicaSetChangeControllerRef(t *testing.T) {
864 logger, ctx := ktesting.NewTestContext(t)
865
866 f := newFixture(t)
867
868 d1 := newDeployment("d1", 1, nil, nil, nil, map[string]string{"foo": "bar"})
869 d2 := newDeployment("d2", 1, nil, nil, nil, map[string]string{"foo": "bar"})
870
871 rs := newReplicaSet(d1, "rs1", 1)
872
873 f.dLister = append(f.dLister, d1, d2)
874 f.rsLister = append(f.rsLister, rs)
875 f.objects = append(f.objects, d1, d2, rs)
876
877
878
879 dc, _, err := f.newController(ctx)
880 if err != nil {
881 t.Fatalf("error creating Deployment controller: %v", err)
882 }
883
884
885 prev := *rs
886 prev.OwnerReferences = []metav1.OwnerReference{*metav1.NewControllerRef(d2, controllerKind)}
887 next := *rs
888 bumpResourceVersion(&next)
889 dc.updateReplicaSet(logger, &prev, &next)
890 if got, want := dc.queue.Len(), 2; got != want {
891 t.Fatalf("queue.Len() = %v, want %v", got, want)
892 }
893 }
894
895 func TestUpdateReplicaSetRelease(t *testing.T) {
896 logger, ctx := ktesting.NewTestContext(t)
897
898 f := newFixture(t)
899
900 d1 := newDeployment("d1", 1, nil, nil, nil, map[string]string{"foo": "bar"})
901 d2 := newDeployment("d2", 1, nil, nil, nil, map[string]string{"foo": "bar"})
902
903 rs := newReplicaSet(d1, "rs1", 1)
904
905 f.dLister = append(f.dLister, d1, d2)
906 f.rsLister = append(f.rsLister, rs)
907 f.objects = append(f.objects, d1, d2, rs)
908
909
910
911 dc, _, err := f.newController(ctx)
912 if err != nil {
913 t.Fatalf("error creating Deployment controller: %v", err)
914 }
915
916
917 prev := *rs
918 next := *rs
919 next.OwnerReferences = nil
920 bumpResourceVersion(&next)
921 dc.updateReplicaSet(logger, &prev, &next)
922 if got, want := dc.queue.Len(), 2; got != want {
923 t.Fatalf("queue.Len() = %v, want %v", got, want)
924 }
925 }
926
927 func TestDeleteReplicaSet(t *testing.T) {
928 logger, ctx := ktesting.NewTestContext(t)
929
930 f := newFixture(t)
931
932 d1 := newDeployment("d1", 1, nil, nil, nil, map[string]string{"foo": "bar"})
933 d2 := newDeployment("d2", 1, nil, nil, nil, map[string]string{"foo": "bar"})
934
935
936
937 rs1 := newReplicaSet(d1, "rs1", 1)
938 rs2 := newReplicaSet(d2, "rs2", 1)
939
940 f.dLister = append(f.dLister, d1, d2)
941 f.rsLister = append(f.rsLister, rs1, rs2)
942 f.objects = append(f.objects, d1, d2, rs1, rs2)
943
944
945
946 dc, _, err := f.newController(ctx)
947 if err != nil {
948 t.Fatalf("error creating Deployment controller: %v", err)
949 }
950
951 dc.deleteReplicaSet(logger, rs1)
952 if got, want := dc.queue.Len(), 1; got != want {
953 t.Fatalf("queue.Len() = %v, want %v", got, want)
954 }
955 key, done := dc.queue.Get()
956 if key == nil || done {
957 t.Fatalf("failed to enqueue controller for rs %v", rs1.Name)
958 }
959 expectedKey, _ := controller.KeyFunc(d1)
960 if got, want := key.(string), expectedKey; got != want {
961 t.Errorf("queue.Get() = %v, want %v", got, want)
962 }
963
964 dc.deleteReplicaSet(logger, rs2)
965 if got, want := dc.queue.Len(), 1; got != want {
966 t.Fatalf("queue.Len() = %v, want %v", got, want)
967 }
968 key, done = dc.queue.Get()
969 if key == nil || done {
970 t.Fatalf("failed to enqueue controller for rs %v", rs2.Name)
971 }
972 expectedKey, _ = controller.KeyFunc(d2)
973 if got, want := key.(string), expectedKey; got != want {
974 t.Errorf("queue.Get() = %v, want %v", got, want)
975 }
976 }
977
978 func TestDeleteReplicaSetOrphan(t *testing.T) {
979 logger, ctx := ktesting.NewTestContext(t)
980
981 f := newFixture(t)
982
983 d1 := newDeployment("d1", 1, nil, nil, nil, map[string]string{"foo": "bar"})
984 d2 := newDeployment("d2", 1, nil, nil, nil, map[string]string{"foo": "bar"})
985
986
987 rs := newReplicaSet(d1, "rs1", 1)
988 rs.OwnerReferences = nil
989
990 f.dLister = append(f.dLister, d1, d2)
991 f.rsLister = append(f.rsLister, rs)
992 f.objects = append(f.objects, d1, d2, rs)
993
994
995
996 dc, _, err := f.newController(ctx)
997 if err != nil {
998 t.Fatalf("error creating Deployment controller: %v", err)
999 }
1000
1001 dc.deleteReplicaSet(logger, rs)
1002 if got, want := dc.queue.Len(), 0; got != want {
1003 t.Fatalf("queue.Len() = %v, want %v", got, want)
1004 }
1005 }
1006
1007 func BenchmarkGetPodMapForDeployment(b *testing.B) {
1008 _, ctx := ktesting.NewTestContext(b)
1009
1010 f := newFixture(b)
1011
1012 d := newDeployment("foo", 1, nil, nil, nil, map[string]string{"foo": "bar"})
1013
1014 rs1 := newReplicaSet(d, "rs1", 1)
1015 rs2 := newReplicaSet(d, "rs2", 1)
1016
1017 var pods []*v1.Pod
1018 var objects []runtime.Object
1019 for i := 0; i < 100; i++ {
1020 p1, p2 := generatePodFromRS(rs1), generatePodFromRS(rs2)
1021 p1.Name, p2.Name = p1.Name+fmt.Sprintf("-%d", i), p2.Name+fmt.Sprintf("-%d", i)
1022 pods = append(pods, p1, p2)
1023 objects = append(objects, p1, p2)
1024 }
1025
1026 f.dLister = append(f.dLister, d)
1027 f.rsLister = append(f.rsLister, rs1, rs2)
1028 f.podLister = append(f.podLister, pods...)
1029 f.objects = append(f.objects, d, rs1, rs2)
1030 f.objects = append(f.objects, objects...)
1031
1032
1033 c, informers, err := f.newController(ctx)
1034 if err != nil {
1035 b.Fatalf("error creating Deployment controller: %v", err)
1036 }
1037 stopCh := make(chan struct{})
1038 defer close(stopCh)
1039 informers.Start(stopCh)
1040
1041 b.ReportAllocs()
1042 b.ResetTimer()
1043 for n := 0; n < b.N; n++ {
1044 m, err := c.getPodMapForDeployment(d, f.rsLister)
1045 if err != nil {
1046 b.Fatalf("getPodMapForDeployment() error: %v", err)
1047 }
1048 if len(m) != 2 {
1049 b.Errorf("Invalid map size, expected 2, got: %d", len(m))
1050 }
1051 }
1052 }
1053
1054 func bumpResourceVersion(obj metav1.Object) {
1055 ver, _ := strconv.ParseInt(obj.GetResourceVersion(), 10, 32)
1056 obj.SetResourceVersion(strconv.FormatInt(ver+1, 10))
1057 }
1058
1059
1060 func generatePodFromRS(rs *apps.ReplicaSet) *v1.Pod {
1061 trueVar := true
1062 return &v1.Pod{
1063 ObjectMeta: metav1.ObjectMeta{
1064 Name: rs.Name + "-pod",
1065 Namespace: rs.Namespace,
1066 Labels: rs.Spec.Selector.MatchLabels,
1067 OwnerReferences: []metav1.OwnerReference{
1068 {UID: rs.UID, APIVersion: "v1beta1", Kind: "ReplicaSet", Name: rs.Name, Controller: &trueVar},
1069 },
1070 },
1071 Spec: rs.Spec.Template.Spec,
1072 }
1073 }
1074
View as plain text