1
16
17 package history
18
19 import (
20 "bytes"
21 "context"
22 "encoding/json"
23 "fmt"
24 "reflect"
25 "testing"
26 "time"
27
28 apps "k8s.io/api/apps/v1"
29 v1 "k8s.io/api/core/v1"
30 "k8s.io/client-go/informers"
31 "k8s.io/client-go/kubernetes/fake"
32 clientscheme "k8s.io/client-go/kubernetes/scheme"
33 core "k8s.io/client-go/testing"
34 "k8s.io/kubernetes/pkg/api/legacyscheme"
35 "k8s.io/kubernetes/pkg/controller"
36
37 "k8s.io/apimachinery/pkg/api/errors"
38 "k8s.io/apimachinery/pkg/api/resource"
39 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
40 "k8s.io/apimachinery/pkg/labels"
41 "k8s.io/apimachinery/pkg/runtime"
42 "k8s.io/apimachinery/pkg/types"
43 "k8s.io/apimachinery/pkg/util/strategicpatch"
44 "k8s.io/utils/pointer"
45 )
46
47 func TestRealHistory_ListControllerRevisions(t *testing.T) {
48 type testcase struct {
49 name string
50 parent metav1.Object
51 selector labels.Selector
52 revisions []*apps.ControllerRevision
53 want map[string]bool
54 }
55 testFn := func(test *testcase, t *testing.T) {
56 client := fake.NewSimpleClientset()
57 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
58
59 stop := make(chan struct{})
60 defer close(stop)
61 informerFactory.Start(stop)
62 informer := informerFactory.Apps().V1().ControllerRevisions()
63 informerFactory.WaitForCacheSync(stop)
64 for i := range test.revisions {
65 informer.Informer().GetIndexer().Add(test.revisions[i])
66 }
67
68 history := NewHistory(client, informer.Lister())
69 revisions, err := history.ListControllerRevisions(test.parent, test.selector)
70 if err != nil {
71 t.Errorf("%s: %s", test.name, err)
72 }
73 got := make(map[string]bool)
74 for i := range revisions {
75 got[revisions[i].Name] = true
76 }
77 if !reflect.DeepEqual(test.want, got) {
78 t.Errorf("%s: want %v got %v", test.name, test.want, got)
79 }
80 }
81 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
82 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
83 sel1, err := metav1.LabelSelectorAsSelector(ss1.Spec.Selector)
84 if err != nil {
85 t.Fatal(err)
86 }
87 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, nil)
88 if err != nil {
89 t.Fatal(err)
90 }
91 ss1Rev1.Namespace = ss1.Namespace
92 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, nil)
93 if err != nil {
94 t.Fatal(err)
95 }
96 ss1Rev2.Namespace = ss1.Namespace
97 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, nil)
98 if err != nil {
99 t.Fatal(err)
100 }
101 ss2Rev1.Namespace = ss2.Namespace
102 ss1Orphan, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 3, nil)
103 if err != nil {
104 t.Fatal(err)
105 }
106 ss1Orphan.Namespace = ss1.Namespace
107 ss1Orphan.OwnerReferences = nil
108
109 tests := []testcase{
110 {
111 name: "selects none",
112 parent: &ss1.ObjectMeta,
113 selector: sel1,
114 revisions: nil,
115 want: map[string]bool{},
116 },
117 {
118 name: "selects all",
119 parent: &ss1.ObjectMeta,
120 selector: sel1,
121 revisions: []*apps.ControllerRevision{ss1Rev1, ss1Rev2},
122 want: map[string]bool{ss1Rev1.Name: true, ss1Rev2.Name: true},
123 },
124 {
125 name: "doesn't select another Objects history",
126 parent: &ss1.ObjectMeta,
127 selector: sel1,
128 revisions: []*apps.ControllerRevision{ss1Rev1, ss1Rev2, ss2Rev1},
129 want: map[string]bool{ss1Rev1.Name: true, ss1Rev2.Name: true},
130 },
131 {
132 name: "selects orphans",
133 parent: &ss1.ObjectMeta,
134 selector: sel1,
135 revisions: []*apps.ControllerRevision{ss1Rev1, ss1Rev2, ss1Orphan},
136 want: map[string]bool{ss1Rev1.Name: true, ss1Rev2.Name: true, ss1Orphan.Name: true},
137 },
138 }
139 for i := range tests {
140 testFn(&tests[i], t)
141 }
142 }
143
144 func TestFakeHistory_ListControllerRevisions(t *testing.T) {
145 type testcase struct {
146 name string
147 parent metav1.Object
148 selector labels.Selector
149 revisions []*apps.ControllerRevision
150 want map[string]bool
151 }
152 testFn := func(test *testcase, t *testing.T) {
153 client := fake.NewSimpleClientset()
154 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
155
156 stop := make(chan struct{})
157 defer close(stop)
158 informerFactory.Start(stop)
159 informer := informerFactory.Apps().V1().ControllerRevisions()
160 informerFactory.WaitForCacheSync(stop)
161 for i := range test.revisions {
162 informer.Informer().GetIndexer().Add(test.revisions[i])
163 }
164
165 history := NewFakeHistory(informer)
166 revisions, err := history.ListControllerRevisions(test.parent, test.selector)
167 if err != nil {
168 t.Errorf("%s: %s", test.name, err)
169 }
170 got := make(map[string]bool)
171 for i := range revisions {
172 got[revisions[i].Name] = true
173 }
174 if !reflect.DeepEqual(test.want, got) {
175 t.Errorf("%s: want %v got %v", test.name, test.want, got)
176 }
177 }
178 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
179 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
180 sel1, err := metav1.LabelSelectorAsSelector(ss1.Spec.Selector)
181 if err != nil {
182 t.Fatal(err)
183 }
184 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, nil)
185 if err != nil {
186 t.Fatal(err)
187 }
188 ss1Rev1.Namespace = ss1.Namespace
189 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, nil)
190 if err != nil {
191 t.Fatal(err)
192 }
193 ss1Rev2.Namespace = ss1.Namespace
194 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, nil)
195 if err != nil {
196 t.Fatal(err)
197 }
198 ss2Rev1.Namespace = ss2.Namespace
199 ss1Orphan, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 3, nil)
200 if err != nil {
201 t.Fatal(err)
202 }
203 ss1Orphan.Namespace = ss1.Namespace
204 ss1Orphan.OwnerReferences = nil
205
206 tests := []testcase{
207 {
208 name: "selects none",
209 parent: &ss1.ObjectMeta,
210 selector: sel1,
211 revisions: nil,
212 want: map[string]bool{},
213 },
214 {
215 name: "selects all",
216 parent: &ss1.ObjectMeta,
217 selector: sel1,
218 revisions: []*apps.ControllerRevision{ss1Rev1, ss1Rev2},
219 want: map[string]bool{ss1Rev1.Name: true, ss1Rev2.Name: true},
220 },
221 {
222 name: "doesn't select another Objects history",
223 parent: &ss1.ObjectMeta,
224 selector: sel1,
225 revisions: []*apps.ControllerRevision{ss1Rev1, ss1Rev2, ss2Rev1},
226 want: map[string]bool{ss1Rev1.Name: true, ss1Rev2.Name: true},
227 },
228 {
229 name: "selects orphans",
230 parent: &ss1.ObjectMeta,
231 selector: sel1,
232 revisions: []*apps.ControllerRevision{ss1Rev1, ss1Rev2, ss1Orphan},
233 want: map[string]bool{ss1Rev1.Name: true, ss1Rev2.Name: true, ss1Orphan.Name: true},
234 },
235 }
236 for i := range tests {
237 testFn(&tests[i], t)
238 }
239 }
240
241 func TestRealHistory_CreateControllerRevision(t *testing.T) {
242 type testcase struct {
243 name string
244 parent metav1.Object
245 revision *apps.ControllerRevision
246 existing []struct {
247 parent metav1.Object
248 revision *apps.ControllerRevision
249 }
250 rename bool
251 }
252 testFn := func(test *testcase, t *testing.T) {
253 client := fake.NewSimpleClientset()
254 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
255 stop := make(chan struct{})
256 defer close(stop)
257 informerFactory.Start(stop)
258 informer := informerFactory.Apps().V1().ControllerRevisions()
259 informerFactory.WaitForCacheSync(stop)
260 history := NewHistory(client, informer.Lister())
261
262 var collisionCount int32
263 for _, item := range test.existing {
264 _, err := client.AppsV1().ControllerRevisions(item.parent.GetNamespace()).Create(context.TODO(), item.revision, metav1.CreateOptions{})
265 if err != nil {
266 t.Fatal(err)
267 }
268 }
269
270 collisionCount = 0
271 created, err := history.CreateControllerRevision(test.parent, test.revision, &collisionCount)
272 if err != nil {
273 t.Errorf("%s: %s", test.name, err)
274 }
275
276 if test.rename {
277 if created.Name == test.revision.Name {
278 t.Errorf("%s: wanted rename got %s %s", test.name, created.Name, test.revision.Name)
279 }
280 expectedName := ControllerRevisionName(test.parent.GetName(), HashControllerRevision(test.revision, &collisionCount))
281 if created.Name != expectedName {
282 t.Errorf("%s: on name collision wanted new name %s got %s", test.name, expectedName, created.Name)
283 }
284
285
286 _, err = history.CreateControllerRevision(test.parent, test.revision, &collisionCount)
287 if err != nil {
288 t.Errorf("%s: %s", test.name, err)
289 }
290 if collisionCount != 1 {
291 t.Errorf("%s: on second name collision wanted collisionCount 1 got %d", test.name, collisionCount)
292 }
293 }
294 if !test.rename && created.Name != test.revision.Name {
295 t.Errorf("%s: wanted %s got %s", test.name, test.revision.Name, created.Name)
296 }
297 }
298 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
299 ss1.Status.CollisionCount = new(int32)
300 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
301 ss2.Status.CollisionCount = new(int32)
302 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
303 if err != nil {
304 t.Fatal(err)
305 }
306 ss1Rev1.Namespace = ss1.Namespace
307
308
309
310
311
312 modTemplate := ss1.Spec.Template.DeepCopy()
313 modTemplate.Labels["foo"] = "not_bar"
314 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(modTemplate), 2, ss1.Status.CollisionCount)
315 ss1Rev2.Name = ss1Rev1.Name
316 ss1Rev2.Labels[ControllerRevisionHashLabel] = ss1Rev1.Labels[ControllerRevisionHashLabel]
317 if err != nil {
318 t.Fatal(err)
319 }
320 ss1Rev2.Namespace = ss1.Namespace
321 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, ss2.Status.CollisionCount)
322 if err != nil {
323 t.Fatal(err)
324 }
325 ss2Rev1.Namespace = ss2.Namespace
326 tests := []testcase{
327 {
328 name: "creates new",
329 parent: &ss1.ObjectMeta,
330 revision: ss1Rev1,
331 existing: nil,
332
333 rename: false,
334 },
335 {
336 name: "create doesn't conflict when parents differ",
337 parent: &ss2.ObjectMeta,
338 revision: ss2Rev1,
339 existing: []struct {
340 parent metav1.Object
341 revision *apps.ControllerRevision
342 }{
343 {
344 parent: ss1,
345 revision: ss1Rev1,
346 },
347 },
348
349 rename: false,
350 },
351 {
352 name: "create renames on conflict",
353 parent: &ss1.ObjectMeta,
354 revision: ss1Rev1,
355 existing: []struct {
356 parent metav1.Object
357 revision *apps.ControllerRevision
358 }{
359 {
360 parent: ss1,
361 revision: ss1Rev2,
362 },
363 },
364 rename: true,
365 },
366 }
367 for i := range tests {
368 testFn(&tests[i], t)
369 }
370 }
371
372 func TestFakeHistory_CreateControllerRevision(t *testing.T) {
373 type testcase struct {
374 name string
375 parent metav1.Object
376 revision *apps.ControllerRevision
377 existing []struct {
378 parent metav1.Object
379 revision *apps.ControllerRevision
380 }
381 rename bool
382 }
383 testFn := func(test *testcase, t *testing.T) {
384 client := fake.NewSimpleClientset()
385 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
386
387 stop := make(chan struct{})
388 defer close(stop)
389 informerFactory.Start(stop)
390 informer := informerFactory.Apps().V1().ControllerRevisions()
391 informerFactory.WaitForCacheSync(stop)
392 history := NewFakeHistory(informer)
393
394 var collisionCount int32
395 for i := range test.existing {
396 _, err := history.CreateControllerRevision(test.existing[i].parent, test.existing[i].revision, &collisionCount)
397 if err != nil {
398 t.Fatal(err)
399 }
400 }
401
402 collisionCount = 0
403 created, err := history.CreateControllerRevision(test.parent, test.revision, &collisionCount)
404 if err != nil {
405 t.Errorf("%s: %s", test.name, err)
406 }
407
408 if test.rename {
409 if created.Name == test.revision.Name {
410 t.Errorf("%s: wanted rename got %s %s", test.name, created.Name, test.revision.Name)
411 }
412 expectedName := ControllerRevisionName(test.parent.GetName(), HashControllerRevision(test.revision, &collisionCount))
413 if created.Name != expectedName {
414 t.Errorf("%s: on name collision wanted new name %s got %s", test.name, expectedName, created.Name)
415 }
416
417
418 _, err = history.CreateControllerRevision(test.parent, test.revision, &collisionCount)
419 if err != nil {
420 t.Errorf("%s: %s", test.name, err)
421 }
422 if collisionCount != 2 {
423 t.Errorf("%s: on second name collision wanted collisionCount 1 got %d", test.name, collisionCount)
424 }
425 }
426 if !test.rename && created.Name != test.revision.Name {
427 t.Errorf("%s: wanted %s got %s", test.name, test.revision.Name, created.Name)
428 }
429 }
430 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
431 ss1.Status.CollisionCount = new(int32)
432 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
433 ss2.Status.CollisionCount = new(int32)
434 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
435 if err != nil {
436 t.Fatal(err)
437 }
438 ss1Rev1.Namespace = ss1.Namespace
439 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
440 if err != nil {
441 t.Fatal(err)
442 }
443 ss1Rev2.Namespace = ss1.Namespace
444 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, ss2.Status.CollisionCount)
445 if err != nil {
446 t.Fatal(err)
447 }
448 ss2Rev1.Namespace = ss2.Namespace
449 tests := []testcase{
450 {
451 name: "creates new",
452 parent: &ss1.ObjectMeta,
453 revision: ss1Rev1,
454 existing: nil,
455
456 rename: false,
457 },
458 {
459 name: "create doesn't conflict when parents differ",
460 parent: &ss2.ObjectMeta,
461 revision: ss2Rev1,
462 existing: []struct {
463 parent metav1.Object
464 revision *apps.ControllerRevision
465 }{
466 {
467 parent: ss1,
468 revision: ss1Rev1,
469 },
470 },
471
472 rename: false,
473 },
474 {
475 name: "create renames on conflict",
476 parent: &ss1.ObjectMeta,
477 revision: ss1Rev1,
478 existing: []struct {
479 parent metav1.Object
480 revision *apps.ControllerRevision
481 }{
482 {
483 parent: ss1,
484 revision: ss1Rev1,
485 },
486 },
487 rename: true,
488 },
489 }
490 for i := range tests {
491 testFn(&tests[i], t)
492 }
493 }
494
495 func TestRealHistory_UpdateControllerRevision(t *testing.T) {
496 conflictAttempts := 0
497 type testcase struct {
498 name string
499 revision *apps.ControllerRevision
500 newRevision int64
501 existing []struct {
502 parent metav1.Object
503 revision *apps.ControllerRevision
504 }
505 reactor core.ReactionFunc
506 err bool
507 }
508 conflictSuccess := func(action core.Action) (bool, runtime.Object, error) {
509 defer func() {
510 conflictAttempts++
511 }()
512 switch action.(type) {
513
514 case core.UpdateActionImpl:
515 update := action.(core.UpdateAction)
516 if conflictAttempts < 2 {
517 return true, update.GetObject(), errors.NewConflict(update.GetResource().GroupResource(), "", fmt.Errorf("conflict"))
518 }
519 return true, update.GetObject(), nil
520 default:
521 return false, nil, nil
522 }
523 }
524 internalError := func(action core.Action) (bool, runtime.Object, error) {
525 switch action.(type) {
526 case core.UpdateActionImpl:
527 return true, nil, errors.NewInternalError(fmt.Errorf("internal error"))
528 default:
529 return false, nil, nil
530 }
531 }
532
533 testFn := func(test *testcase, t *testing.T) {
534 client := fake.NewSimpleClientset()
535
536 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
537 stop := make(chan struct{})
538 defer close(stop)
539 informerFactory.Start(stop)
540 informer := informerFactory.Apps().V1().ControllerRevisions()
541 informerFactory.WaitForCacheSync(stop)
542 history := NewHistory(client, informer.Lister())
543 var collisionCount int32
544 for i := range test.existing {
545 _, err := history.CreateControllerRevision(test.existing[i].parent, test.existing[i].revision, &collisionCount)
546 if err != nil {
547 t.Fatal(err)
548 }
549 }
550 if test.reactor != nil {
551 client.PrependReactor("*", "*", test.reactor)
552 }
553 updated, err := history.UpdateControllerRevision(test.revision, test.newRevision)
554 if !test.err && err != nil {
555 t.Errorf("%s: %s", test.name, err)
556 }
557 if !test.err && updated.Revision != test.newRevision {
558 t.Errorf("%s: got %d want %d", test.name, updated.Revision, test.newRevision)
559 }
560 if test.err && err == nil {
561 t.Errorf("%s: expected error", test.name)
562 }
563 }
564 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
565 ss1.Status.CollisionCount = new(int32)
566 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
567 if err != nil {
568 t.Fatal(err)
569 }
570 ss1Rev1.Namespace = ss1.Namespace
571 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
572 if err != nil {
573 t.Fatal(err)
574 }
575 ss1Rev2.Namespace = ss1.Namespace
576
577 tests := []testcase{
578 {
579 name: "update succeeds",
580 revision: ss1Rev1,
581 newRevision: ss1Rev1.Revision + 1,
582 existing: []struct {
583 parent metav1.Object
584 revision *apps.ControllerRevision
585 }{
586 {
587 parent: ss1,
588 revision: ss1Rev1,
589 },
590 },
591 reactor: nil,
592 err: false,
593 },
594 {
595 name: "update succeeds no noop",
596 revision: ss1Rev1,
597 newRevision: ss1Rev1.Revision,
598 existing: []struct {
599 parent metav1.Object
600 revision *apps.ControllerRevision
601 }{
602 {
603 parent: ss1,
604 revision: ss1Rev1,
605 },
606 },
607 reactor: nil,
608 err: false,
609 }, {
610 name: "update fails on error",
611 revision: ss1Rev1,
612 newRevision: ss1Rev1.Revision + 10,
613 existing: []struct {
614 parent metav1.Object
615 revision *apps.ControllerRevision
616 }{
617 {
618 parent: ss1,
619 revision: ss1Rev1,
620 },
621 },
622 reactor: internalError,
623 err: true,
624 },
625 {
626 name: "update on succeeds on conflict",
627 revision: ss1Rev1,
628 newRevision: ss1Rev1.Revision + 1,
629 existing: []struct {
630 parent metav1.Object
631 revision *apps.ControllerRevision
632 }{
633 {
634 parent: ss1,
635 revision: ss1Rev1,
636 },
637 },
638 reactor: conflictSuccess,
639 err: false,
640 },
641 }
642 for i := range tests {
643 conflictAttempts = 0
644 testFn(&tests[i], t)
645 }
646 }
647
648 func TestFakeHistory_UpdateControllerRevision(t *testing.T) {
649 type testcase struct {
650 name string
651 revision *apps.ControllerRevision
652 newRevision int64
653 existing []struct {
654 parent metav1.Object
655 revision *apps.ControllerRevision
656 }
657 err bool
658 }
659
660 testFn := func(test *testcase, t *testing.T) {
661 client := fake.NewSimpleClientset()
662
663 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
664 stop := make(chan struct{})
665 defer close(stop)
666 informerFactory.Start(stop)
667 informer := informerFactory.Apps().V1().ControllerRevisions()
668 informerFactory.WaitForCacheSync(stop)
669 history := NewFakeHistory(informer)
670 var collisionCount int32
671 for i := range test.existing {
672 _, err := history.CreateControllerRevision(test.existing[i].parent, test.existing[i].revision, &collisionCount)
673 if err != nil {
674 t.Fatal(err)
675 }
676 }
677 updated, err := history.UpdateControllerRevision(test.revision, test.newRevision)
678 if !test.err && err != nil {
679 t.Errorf("%s: %s", test.name, err)
680 }
681 if !test.err && updated.Revision != test.newRevision {
682 t.Errorf("%s: got %d want %d", test.name, updated.Revision, test.newRevision)
683 }
684 if test.err && err == nil {
685 t.Errorf("%s: expected error", test.name)
686 }
687 }
688 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
689 ss1.Status.CollisionCount = new(int32)
690
691 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
692 if err != nil {
693 t.Fatal(err)
694 }
695 ss1Rev1.Namespace = ss1.Namespace
696 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
697 if err != nil {
698 t.Fatal(err)
699 }
700 ss1Rev2.Namespace = ss1.Namespace
701 tests := []testcase{
702 {
703 name: "update succeeds",
704 revision: ss1Rev1,
705 newRevision: ss1Rev1.Revision + 1,
706 existing: []struct {
707 parent metav1.Object
708 revision *apps.ControllerRevision
709 }{
710 {
711 parent: ss1,
712 revision: ss1Rev1,
713 },
714 },
715 err: false,
716 },
717 {
718 name: "update succeeds no noop",
719 revision: ss1Rev1,
720 newRevision: ss1Rev1.Revision,
721 existing: []struct {
722 parent metav1.Object
723 revision *apps.ControllerRevision
724 }{
725 {
726 parent: ss1,
727 revision: ss1Rev1,
728 },
729 },
730 err: false,
731 },
732 }
733 for i := range tests {
734 testFn(&tests[i], t)
735 }
736 }
737
738 func TestRealHistory_DeleteControllerRevision(t *testing.T) {
739 type testcase struct {
740 name string
741 revision *apps.ControllerRevision
742 existing []struct {
743 parent metav1.Object
744 revision *apps.ControllerRevision
745 }
746 err bool
747 }
748 testFn := func(test *testcase, t *testing.T) {
749 client := fake.NewSimpleClientset()
750 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
751
752 stop := make(chan struct{})
753 defer close(stop)
754 informerFactory.Start(stop)
755 informer := informerFactory.Apps().V1().ControllerRevisions()
756 informerFactory.WaitForCacheSync(stop)
757 history := NewHistory(client, informer.Lister())
758 var collisionCount int32
759 for i := range test.existing {
760 _, err := history.CreateControllerRevision(test.existing[i].parent, test.existing[i].revision, &collisionCount)
761 if err != nil {
762 t.Fatal(err)
763 }
764 }
765 err := history.DeleteControllerRevision(test.revision)
766 if !test.err && err != nil {
767 t.Errorf("%s: %s", test.name, err)
768 }
769 if test.err && err == nil {
770 t.Errorf("%s: expected error", test.name)
771 }
772 }
773 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
774 ss1.Status.CollisionCount = new(int32)
775 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
776 ss2.Status.CollisionCount = new(int32)
777 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
778 if err != nil {
779 t.Fatal(err)
780 }
781 ss1Rev1.Namespace = ss1.Namespace
782 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
783 if err != nil {
784 t.Fatal(err)
785 }
786 ss1Rev2.Namespace = ss1.Namespace
787 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, ss2.Status.CollisionCount)
788 if err != nil {
789 t.Fatal(err)
790 }
791 ss2Rev1.Namespace = ss2.Namespace
792 ss2Rev2, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 2, ss2.Status.CollisionCount)
793 if err != nil {
794 t.Fatal(err)
795 }
796 ss2Rev2.Namespace = ss2.Namespace
797 tests := []testcase{
798 {
799 name: "delete empty fails",
800 revision: ss1Rev1,
801 existing: nil,
802 err: true,
803 },
804 {
805 name: "delete existing succeeds",
806 revision: ss1Rev1,
807 existing: []struct {
808 parent metav1.Object
809 revision *apps.ControllerRevision
810 }{
811 {
812 parent: ss1,
813 revision: ss1Rev1,
814 },
815 },
816 err: false,
817 }, {
818 name: "delete non-existing fails",
819 revision: ss1Rev1,
820 existing: []struct {
821 parent metav1.Object
822 revision *apps.ControllerRevision
823 }{
824 {
825 parent: ss2,
826 revision: ss2Rev1,
827 },
828 {
829 parent: ss2,
830 revision: ss2Rev2,
831 },
832 },
833 err: true,
834 },
835 }
836 for i := range tests {
837 testFn(&tests[i], t)
838 }
839 }
840
841 func TestFakeHistory_DeleteControllerRevision(t *testing.T) {
842 type testcase struct {
843 name string
844 revision *apps.ControllerRevision
845 existing []struct {
846 parent metav1.Object
847 revision *apps.ControllerRevision
848 }
849 err bool
850 }
851 testFn := func(test *testcase, t *testing.T) {
852 client := fake.NewSimpleClientset()
853 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
854
855 stop := make(chan struct{})
856 defer close(stop)
857 informerFactory.Start(stop)
858 informer := informerFactory.Apps().V1().ControllerRevisions()
859 informerFactory.WaitForCacheSync(stop)
860 history := NewFakeHistory(informer)
861 var collisionCount int32
862 for i := range test.existing {
863 _, err := history.CreateControllerRevision(test.existing[i].parent, test.existing[i].revision, &collisionCount)
864 if err != nil {
865 t.Fatal(err)
866 }
867 }
868 err := history.DeleteControllerRevision(test.revision)
869 if !test.err && err != nil {
870 t.Errorf("%s: %s", test.name, err)
871 }
872 if test.err && err == nil {
873 t.Errorf("%s: expected error", test.name)
874 }
875 }
876 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
877 ss1.Status.CollisionCount = new(int32)
878 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
879 ss2.Status.CollisionCount = new(int32)
880 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
881 if err != nil {
882 t.Fatal(err)
883 }
884 ss1Rev1.Namespace = ss1.Namespace
885 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
886 if err != nil {
887 t.Fatal(err)
888 }
889 ss1Rev2.Namespace = ss1.Namespace
890 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, ss2.Status.CollisionCount)
891 if err != nil {
892 t.Fatal(err)
893 }
894 ss2Rev1.Namespace = ss2.Namespace
895 ss2Rev2, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 2, ss2.Status.CollisionCount)
896 if err != nil {
897 t.Fatal(err)
898 }
899 ss2Rev2.Namespace = ss2.Namespace
900 tests := []testcase{
901 {
902 name: "delete empty fails",
903 revision: ss1Rev1,
904 existing: nil,
905 err: true,
906 },
907 {
908 name: "delete existing succeeds",
909 revision: ss1Rev1,
910 existing: []struct {
911 parent metav1.Object
912 revision *apps.ControllerRevision
913 }{
914 {
915 parent: ss1,
916 revision: ss1Rev1,
917 },
918 },
919 err: false,
920 }, {
921 name: "delete non-existing fails",
922 revision: ss1Rev1,
923 existing: []struct {
924 parent metav1.Object
925 revision *apps.ControllerRevision
926 }{
927 {
928 parent: ss2,
929 revision: ss2Rev1,
930 },
931 {
932 parent: ss2,
933 revision: ss2Rev2,
934 },
935 },
936 err: true,
937 },
938 }
939 for i := range tests {
940 testFn(&tests[i], t)
941 }
942 }
943
944 func TestRealHistory_AdoptControllerRevision(t *testing.T) {
945 type testcase struct {
946 name string
947 parent metav1.Object
948 revision *apps.ControllerRevision
949 existing []struct {
950 parent metav1.Object
951 revision *apps.ControllerRevision
952 }
953 err bool
954 }
955 testFn := func(test *testcase, t *testing.T) {
956 client := fake.NewSimpleClientset()
957 client.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
958 switch action := action.(type) {
959 case core.PatchActionImpl:
960 var found *apps.ControllerRevision
961 for i := range test.existing {
962 if test.revision.Name == test.existing[i].revision.Name &&
963 test.revision.Namespace == test.existing[i].revision.Namespace {
964 found = test.existing[i].revision
965 break
966 }
967 }
968 if found == nil {
969 return true, nil, errors.NewNotFound(apps.Resource("controllerrevisions"), test.revision.Name)
970 }
971 b, err := strategicpatch.StrategicMergePatch(
972 []byte(runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(apps.SchemeGroupVersion), test.revision)),
973 action.GetPatch(), test.revision)
974 if err != nil {
975 return true, nil, err
976 }
977 obj, err := runtime.Decode(clientscheme.Codecs.LegacyCodec(apps.SchemeGroupVersion), b)
978 if err != nil {
979 return true, nil, err
980 }
981 patched, err := legacyscheme.Scheme.ConvertToVersion(obj, apps.SchemeGroupVersion)
982 if err != nil {
983 return true, nil, err
984 }
985 return true, patched, err
986 default:
987 return false, nil, nil
988 }
989
990 })
991 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
992 stop := make(chan struct{})
993 defer close(stop)
994 informerFactory.Start(stop)
995 informer := informerFactory.Apps().V1().ControllerRevisions()
996 informerFactory.WaitForCacheSync(stop)
997
998 history := NewHistory(client, informer.Lister())
999 var collisionCount int32
1000 for i := range test.existing {
1001 _, err := history.CreateControllerRevision(test.existing[i].parent, test.existing[i].revision, &collisionCount)
1002 if err != nil {
1003 t.Fatal(err)
1004 }
1005 }
1006 adopted, err := history.AdoptControllerRevision(test.parent, parentKind, test.revision)
1007 if !test.err && err != nil {
1008 t.Errorf("%s: %s", test.name, err)
1009 }
1010 if !test.err && !metav1.IsControlledBy(adopted, test.parent) {
1011 t.Errorf("%s: adoption failed", test.name)
1012 }
1013 if test.err && err == nil {
1014 t.Errorf("%s: expected error", test.name)
1015 }
1016 }
1017
1018 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
1019 ss1.Status.CollisionCount = new(int32)
1020 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
1021 ss2.Status.CollisionCount = new(int32)
1022 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
1023 if err != nil {
1024 t.Fatal(err)
1025 }
1026 ss1Rev1.Namespace = ss1.Namespace
1027 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
1028 if err != nil {
1029 t.Fatal(err)
1030 }
1031 ss1Rev2.Namespace = ss1.Namespace
1032 ss1Rev2.OwnerReferences = []metav1.OwnerReference{}
1033 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, ss2.Status.CollisionCount)
1034 if err != nil {
1035 t.Fatal(err)
1036 }
1037 ss2Rev1.Namespace = ss2.Namespace
1038 tests := []testcase{
1039 {
1040 name: "adopting an orphan succeeds",
1041 parent: ss1,
1042 revision: ss1Rev2,
1043 existing: []struct {
1044 parent metav1.Object
1045 revision *apps.ControllerRevision
1046 }{
1047 {
1048 parent: ss1,
1049 revision: ss1Rev2,
1050 },
1051 },
1052 err: false,
1053 },
1054 {
1055 name: "adopting an owned revision fails",
1056 parent: ss1,
1057 revision: ss2Rev1,
1058 existing: []struct {
1059 parent metav1.Object
1060 revision *apps.ControllerRevision
1061 }{
1062 {
1063 parent: ss2,
1064 revision: ss2Rev1,
1065 },
1066 },
1067 err: true,
1068 },
1069 {
1070 name: "adopting a non-existent revision fails",
1071 parent: ss1,
1072 revision: ss1Rev2,
1073 existing: nil,
1074 err: true,
1075 },
1076 }
1077 for i := range tests {
1078 testFn(&tests[i], t)
1079 }
1080 }
1081
1082 func TestFakeHistory_AdoptControllerRevision(t *testing.T) {
1083 type testcase struct {
1084 name string
1085 parent metav1.Object
1086 parentType *metav1.TypeMeta
1087 revision *apps.ControllerRevision
1088 existing []struct {
1089 parent metav1.Object
1090 revision *apps.ControllerRevision
1091 }
1092 err bool
1093 }
1094 testFn := func(test *testcase, t *testing.T) {
1095 client := fake.NewSimpleClientset()
1096
1097 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
1098 stop := make(chan struct{})
1099 defer close(stop)
1100 informerFactory.Start(stop)
1101 informer := informerFactory.Apps().V1().ControllerRevisions()
1102 informerFactory.WaitForCacheSync(stop)
1103
1104 history := NewFakeHistory(informer)
1105 var collisionCount int32
1106 for i := range test.existing {
1107 _, err := history.CreateControllerRevision(test.existing[i].parent, test.existing[i].revision, &collisionCount)
1108 if err != nil {
1109 t.Fatal(err)
1110 }
1111 }
1112 adopted, err := history.AdoptControllerRevision(test.parent, parentKind, test.revision)
1113 if !test.err && err != nil {
1114 t.Errorf("%s: %s", test.name, err)
1115 }
1116 if !test.err && !metav1.IsControlledBy(adopted, test.parent) {
1117 t.Errorf("%s: adoption failed", test.name)
1118 }
1119 if test.err && err == nil {
1120 t.Errorf("%s: expected error", test.name)
1121 }
1122 }
1123
1124 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
1125 ss1.Status.CollisionCount = new(int32)
1126 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
1127 ss2.Status.CollisionCount = new(int32)
1128 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
1129 if err != nil {
1130 t.Fatal(err)
1131 }
1132 ss1Rev1.Namespace = ss1.Namespace
1133 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
1134 if err != nil {
1135 t.Fatal(err)
1136 }
1137 ss1Rev2.Namespace = ss1.Namespace
1138 ss1Rev2.OwnerReferences = []metav1.OwnerReference{}
1139 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, ss2.Status.CollisionCount)
1140 if err != nil {
1141 t.Fatal(err)
1142 }
1143 ss2Rev1.Namespace = ss2.Namespace
1144 tests := []testcase{
1145 {
1146 name: "adopting an orphan succeeds",
1147 parent: ss1,
1148 parentType: &ss1.TypeMeta,
1149 revision: ss1Rev2,
1150 existing: []struct {
1151 parent metav1.Object
1152 revision *apps.ControllerRevision
1153 }{
1154 {
1155 parent: ss1,
1156 revision: ss1Rev2,
1157 },
1158 },
1159 err: false,
1160 },
1161 {
1162 name: "adopting an owned revision fails",
1163 parent: ss1,
1164 parentType: &ss1.TypeMeta,
1165 revision: ss2Rev1,
1166 existing: []struct {
1167 parent metav1.Object
1168 revision *apps.ControllerRevision
1169 }{
1170 {
1171 parent: ss2,
1172 revision: ss2Rev1,
1173 },
1174 },
1175 err: true,
1176 },
1177 {
1178 name: "adopting a non-existent revision fails",
1179 parent: ss1,
1180 parentType: &ss1.TypeMeta,
1181 revision: ss1Rev2,
1182 existing: nil,
1183 err: true,
1184 },
1185 }
1186 for i := range tests {
1187 testFn(&tests[i], t)
1188 }
1189 }
1190
1191 func TestRealHistory_ReleaseControllerRevision(t *testing.T) {
1192 type testcase struct {
1193 name string
1194 parent metav1.Object
1195 revision *apps.ControllerRevision
1196 existing []struct {
1197 parent metav1.Object
1198 revision *apps.ControllerRevision
1199 }
1200 err bool
1201 }
1202 testFn := func(test *testcase, t *testing.T) {
1203 client := fake.NewSimpleClientset()
1204 client.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
1205 switch action := action.(type) {
1206 case core.PatchActionImpl:
1207 var found *apps.ControllerRevision
1208 for i := range test.existing {
1209 if test.revision.Name == test.existing[i].revision.Name &&
1210 test.revision.Namespace == test.existing[i].revision.Namespace {
1211 found = test.existing[i].revision
1212 break
1213 }
1214 }
1215 if found == nil {
1216 return true, nil, errors.NewNotFound(apps.Resource("controllerrevisions"), test.revision.Name)
1217 }
1218 if !metav1.IsControlledBy(test.revision, test.parent) {
1219 return true, nil, errors.NewInvalid(
1220 test.revision.GroupVersionKind().GroupKind(), test.revision.Name, nil)
1221 }
1222 b, err := strategicpatch.StrategicMergePatch(
1223 []byte(runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(apps.SchemeGroupVersion), test.revision)),
1224 action.GetPatch(), test.revision)
1225 if err != nil {
1226 return true, nil, err
1227 }
1228 obj, err := runtime.Decode(clientscheme.Codecs.LegacyCodec(apps.SchemeGroupVersion), b)
1229 if err != nil {
1230 return true, nil, err
1231 }
1232 patched, err := legacyscheme.Scheme.ConvertToVersion(obj, apps.SchemeGroupVersion)
1233 if err != nil {
1234 return true, nil, err
1235 }
1236 return true, patched, err
1237 default:
1238 return false, nil, nil
1239 }
1240
1241 })
1242 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
1243 stop := make(chan struct{})
1244 defer close(stop)
1245 informerFactory.Start(stop)
1246 informer := informerFactory.Apps().V1().ControllerRevisions()
1247 informerFactory.WaitForCacheSync(stop)
1248
1249 history := NewHistory(client, informer.Lister())
1250 var collisionCount int32
1251 for i := range test.existing {
1252 _, err := history.CreateControllerRevision(test.existing[i].parent, test.existing[i].revision, &collisionCount)
1253 if err != nil {
1254 t.Fatal(err)
1255 }
1256 }
1257 adopted, err := history.ReleaseControllerRevision(test.parent, test.revision)
1258 if !test.err {
1259 if err != nil {
1260 t.Errorf("%s: %s", test.name, err)
1261 }
1262 if adopted == nil {
1263 return
1264 }
1265 if metav1.IsControlledBy(adopted, test.parent) {
1266 t.Errorf("%s: release failed", test.name)
1267 }
1268 }
1269 if test.err && err == nil {
1270 t.Errorf("%s: expected error", test.name)
1271 }
1272 }
1273
1274 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
1275 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
1276 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, nil)
1277 if err != nil {
1278 t.Fatal(err)
1279 }
1280 ss1Rev1.Namespace = ss1.Namespace
1281 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, nil)
1282 if err != nil {
1283 t.Fatal(err)
1284 }
1285 ss1Rev2.Namespace = ss1.Namespace
1286 ss1Rev2.OwnerReferences = []metav1.OwnerReference{}
1287 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, nil)
1288 if err != nil {
1289 t.Fatal(err)
1290 }
1291 ss2Rev1.Namespace = ss2.Namespace
1292 tests := []testcase{
1293 {
1294 name: "releasing an owned revision succeeds",
1295 parent: ss1,
1296 revision: ss1Rev1,
1297 existing: []struct {
1298 parent metav1.Object
1299 revision *apps.ControllerRevision
1300 }{
1301 {
1302 parent: ss1,
1303 revision: ss1Rev1,
1304 },
1305 },
1306 err: false,
1307 },
1308 {
1309 name: "releasing an orphan succeeds",
1310 parent: ss1,
1311 revision: ss1Rev2,
1312 existing: []struct {
1313 parent metav1.Object
1314 revision *apps.ControllerRevision
1315 }{
1316 {
1317 parent: ss1,
1318 revision: ss1Rev2,
1319 },
1320 },
1321 err: false,
1322 },
1323 {
1324 name: "releasing a revision owned by another controller succeeds",
1325 parent: ss1,
1326 revision: ss2Rev1,
1327 existing: []struct {
1328 parent metav1.Object
1329 revision *apps.ControllerRevision
1330 }{
1331 {
1332 parent: ss2,
1333 revision: ss2Rev1,
1334 },
1335 },
1336 err: false,
1337 },
1338 {
1339 name: "releasing a non-existent revision succeeds",
1340 parent: ss1,
1341 revision: ss1Rev1,
1342 existing: nil,
1343 err: false,
1344 },
1345 }
1346 for i := range tests {
1347 testFn(&tests[i], t)
1348 }
1349 }
1350
1351 func TestFakeHistory_ReleaseControllerRevision(t *testing.T) {
1352 type testcase struct {
1353 name string
1354 parent metav1.Object
1355 revision *apps.ControllerRevision
1356 existing []struct {
1357 parent metav1.Object
1358 revision *apps.ControllerRevision
1359 }
1360 err bool
1361 }
1362 testFn := func(test *testcase, t *testing.T) {
1363 client := fake.NewSimpleClientset()
1364 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
1365 stop := make(chan struct{})
1366 defer close(stop)
1367 informerFactory.Start(stop)
1368 informer := informerFactory.Apps().V1().ControllerRevisions()
1369 informerFactory.WaitForCacheSync(stop)
1370 history := NewFakeHistory(informer)
1371 var collisionCount int32
1372 for i := range test.existing {
1373 _, err := history.CreateControllerRevision(test.existing[i].parent, test.existing[i].revision, &collisionCount)
1374 if err != nil {
1375 t.Fatal(err)
1376 }
1377 }
1378 adopted, err := history.ReleaseControllerRevision(test.parent, test.revision)
1379 if !test.err {
1380 if err != nil {
1381 t.Errorf("%s: %s", test.name, err)
1382 }
1383 if adopted == nil {
1384 return
1385 }
1386 if metav1.IsControlledBy(adopted, test.parent) {
1387 t.Errorf("%s: release failed", test.name)
1388 }
1389 }
1390 if test.err && err == nil {
1391 t.Errorf("%s: expected error", test.name)
1392 }
1393 }
1394
1395 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
1396 ss1.Status.CollisionCount = new(int32)
1397 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
1398 ss2.Status.CollisionCount = new(int32)
1399 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
1400 if err != nil {
1401 t.Fatal(err)
1402 }
1403 ss1Rev1.Namespace = ss1.Namespace
1404 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
1405 if err != nil {
1406 t.Fatal(err)
1407 }
1408 ss1Rev2.Namespace = ss1.Namespace
1409 ss1Rev2.OwnerReferences = []metav1.OwnerReference{}
1410 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, ss2.Status.CollisionCount)
1411 if err != nil {
1412 t.Fatal(err)
1413 }
1414 ss2Rev1.Namespace = ss2.Namespace
1415 tests := []testcase{
1416 {
1417 name: "releasing an owned revision succeeds",
1418 parent: ss1,
1419 revision: ss1Rev1,
1420 existing: []struct {
1421 parent metav1.Object
1422 revision *apps.ControllerRevision
1423 }{
1424 {
1425 parent: ss1,
1426 revision: ss1Rev1,
1427 },
1428 },
1429 err: false,
1430 },
1431 {
1432 name: "releasing an orphan succeeds",
1433 parent: ss1,
1434 revision: ss1Rev2,
1435 existing: []struct {
1436 parent metav1.Object
1437 revision *apps.ControllerRevision
1438 }{
1439 {
1440 parent: ss1,
1441 revision: ss1Rev2,
1442 },
1443 },
1444 err: false,
1445 },
1446 {
1447 name: "releasing a revision owned by another controller succeeds",
1448 parent: ss1,
1449 revision: ss2Rev1,
1450 existing: []struct {
1451 parent metav1.Object
1452 revision *apps.ControllerRevision
1453 }{
1454 {
1455 parent: ss2,
1456 revision: ss2Rev1,
1457 },
1458 },
1459 err: false,
1460 },
1461 {
1462 name: "releasing a non-existent revision succeeds",
1463 parent: ss1,
1464 revision: ss1Rev1,
1465 existing: nil,
1466 err: false,
1467 },
1468 }
1469 for i := range tests {
1470 testFn(&tests[i], t)
1471 }
1472 }
1473
1474 func TestFindEqualRevisions(t *testing.T) {
1475 type testcase struct {
1476 name string
1477 revision *apps.ControllerRevision
1478 revisions []*apps.ControllerRevision
1479 want map[string]bool
1480 }
1481 testFn := func(test *testcase, t *testing.T) {
1482 found := FindEqualRevisions(test.revisions, test.revision)
1483 if len(found) != len(test.want) {
1484 t.Errorf("%s: want %d revisions found %d", test.name, len(test.want), len(found))
1485 }
1486 for i := range found {
1487 if !test.want[found[i].Name] {
1488 t.Errorf("%s: wanted %s not found", test.name, found[i].Name)
1489 }
1490
1491 }
1492 }
1493 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
1494 ss1.Status.CollisionCount = new(int32)
1495 ss2 := newStatefulSet(3, "ss2", types.UID("ss2"), map[string]string{"goo": "car"})
1496 ss2.Status.CollisionCount = new(int32)
1497 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
1498 if err != nil {
1499 t.Fatal(err)
1500 }
1501 ss1Rev1.Namespace = ss1.Namespace
1502 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
1503 if err != nil {
1504 t.Fatal(err)
1505 }
1506 ss1Rev2.Namespace = ss1.Namespace
1507 ss1Rev2.OwnerReferences = []metav1.OwnerReference{}
1508 ss2Rev1, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 1, ss2.Status.CollisionCount)
1509 if err != nil {
1510 t.Fatal(err)
1511 }
1512 ss2Rev1.Namespace = ss2.Namespace
1513 ss2Rev2, err := NewControllerRevision(ss2, parentKind, ss2.Spec.Template.Labels, rawTemplate(&ss2.Spec.Template), 2, ss2.Status.CollisionCount)
1514 if err != nil {
1515 t.Fatal(err)
1516 }
1517 ss2Rev2.Namespace = ss2.Namespace
1518 tests := []testcase{
1519 {
1520 name: "finds equivalent",
1521 revision: ss1Rev1,
1522 revisions: []*apps.ControllerRevision{ss1Rev1, ss2Rev1, ss2Rev2},
1523 want: map[string]bool{ss1Rev1.Name: true},
1524 },
1525 {
1526 name: "finds nothing when empty",
1527 revision: ss1Rev1,
1528 revisions: nil,
1529 want: map[string]bool{},
1530 },
1531 {
1532 name: "finds nothing with no matches",
1533 revision: ss1Rev1,
1534 revisions: []*apps.ControllerRevision{ss2Rev2, ss2Rev1},
1535 want: map[string]bool{},
1536 },
1537 }
1538 for i := range tests {
1539 testFn(&tests[i], t)
1540 }
1541 }
1542
1543 func TestSortControllerRevisions(t *testing.T) {
1544 type testcase struct {
1545 name string
1546 revisions []*apps.ControllerRevision
1547 want []string
1548 }
1549 testFn := func(test *testcase, t *testing.T) {
1550 t.Run(test.name, func(t *testing.T) {
1551 SortControllerRevisions(test.revisions)
1552 for i := range test.revisions {
1553 if test.revisions[i].Name != test.want[i] {
1554 t.Errorf("%s: want %s at %d got %s", test.name, test.want[i], i, test.revisions[i].Name)
1555 }
1556 }
1557 })
1558 }
1559 ss1 := newStatefulSet(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"})
1560 ss1.Status.CollisionCount = new(int32)
1561
1562 ss1Rev1, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount)
1563 if err != nil {
1564 t.Fatal(err)
1565 }
1566
1567 ss1Rev1.Namespace = ss1.Namespace
1568 ss1Rev2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount)
1569 if err != nil {
1570 t.Fatal(err)
1571 }
1572
1573 ss1Rev2.Namespace = ss1.Namespace
1574 ss1Rev3, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 3, ss1.Status.CollisionCount)
1575 if err != nil {
1576 t.Fatal(err)
1577 }
1578
1579 ss1Rev3Time2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 3, ss1.Status.CollisionCount)
1580 if err != nil {
1581 t.Fatal(err)
1582 }
1583 ss1Rev3Time2.Namespace = ss1.Namespace
1584 ss1Rev3Time2.CreationTimestamp = metav1.Time{Time: ss1Rev3.CreationTimestamp.Add(time.Second)}
1585
1586 ss1Rev3Time2Name2, err := NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 3, ss1.Status.CollisionCount)
1587 if err != nil {
1588 t.Fatal(err)
1589 }
1590 ss1Rev3Time2Name2.Namespace = ss1.Namespace
1591 ss1Rev3Time2Name2.CreationTimestamp = metav1.Time{Time: ss1Rev3.CreationTimestamp.Add(time.Second)}
1592
1593 tests := []testcase{
1594 {
1595 name: "out of order",
1596 revisions: []*apps.ControllerRevision{ss1Rev2, ss1Rev1, ss1Rev3},
1597 want: []string{ss1Rev1.Name, ss1Rev2.Name, ss1Rev3.Name},
1598 },
1599 {
1600 name: "sorted",
1601 revisions: []*apps.ControllerRevision{ss1Rev1, ss1Rev2, ss1Rev3},
1602 want: []string{ss1Rev1.Name, ss1Rev2.Name, ss1Rev3.Name},
1603 },
1604 {
1605 name: "reversed",
1606 revisions: []*apps.ControllerRevision{ss1Rev3, ss1Rev2, ss1Rev1},
1607 want: []string{ss1Rev1.Name, ss1Rev2.Name, ss1Rev3.Name},
1608 },
1609 {
1610 name: "with ties",
1611 revisions: []*apps.ControllerRevision{ss1Rev3, ss1Rev3Time2, ss1Rev2, ss1Rev1},
1612 want: []string{ss1Rev1.Name, ss1Rev2.Name, ss1Rev3.Name, ss1Rev3Time2.Name, ss1Rev3Time2Name2.Name},
1613 },
1614 {
1615 name: "empty",
1616 revisions: nil,
1617 want: nil,
1618 },
1619 }
1620 for i := range tests {
1621 testFn(&tests[i], t)
1622 }
1623 }
1624
1625 func newStatefulSet(replicas int, name string, uid types.UID, labels map[string]string) *apps.StatefulSet {
1626
1627 var testMatchExpressions []metav1.LabelSelectorRequirement
1628 for key, value := range labels {
1629 sel := metav1.LabelSelectorRequirement{
1630 Key: key,
1631 Operator: metav1.LabelSelectorOpIn,
1632 Values: []string{value},
1633 }
1634 testMatchExpressions = append(testMatchExpressions, sel)
1635 }
1636 return &apps.StatefulSet{
1637 TypeMeta: metav1.TypeMeta{
1638 Kind: "StatefulSet",
1639 APIVersion: "apps/v1",
1640 },
1641 ObjectMeta: metav1.ObjectMeta{
1642 Name: name,
1643 Namespace: v1.NamespaceDefault,
1644 UID: uid,
1645 },
1646 Spec: apps.StatefulSetSpec{
1647 Selector: &metav1.LabelSelector{
1648
1649
1650 MatchLabels: nil,
1651 MatchExpressions: testMatchExpressions,
1652 },
1653 Replicas: pointer.Int32(int32(replicas)),
1654 Template: v1.PodTemplateSpec{
1655 ObjectMeta: metav1.ObjectMeta{
1656 Labels: labels,
1657 },
1658 Spec: v1.PodSpec{
1659 Containers: []v1.Container{
1660 {
1661 Name: "nginx",
1662 Image: "nginx",
1663 VolumeMounts: []v1.VolumeMount{
1664 {Name: "datadir", MountPath: "/tmp/"},
1665 {Name: "home", MountPath: "/home"},
1666 },
1667 },
1668 },
1669 Volumes: []v1.Volume{{
1670 Name: "home",
1671 VolumeSource: v1.VolumeSource{
1672 HostPath: &v1.HostPathVolumeSource{
1673 Path: fmt.Sprintf("/tmp/%v", "home"),
1674 },
1675 }}},
1676 },
1677 },
1678 VolumeClaimTemplates: []v1.PersistentVolumeClaim{
1679 {
1680 ObjectMeta: metav1.ObjectMeta{Name: "datadir"},
1681 Spec: v1.PersistentVolumeClaimSpec{
1682 Resources: v1.VolumeResourceRequirements{
1683 Requests: v1.ResourceList{
1684 v1.ResourceStorage: *resource.NewQuantity(1, resource.BinarySI),
1685 },
1686 },
1687 },
1688 },
1689 },
1690 ServiceName: "governingsvc",
1691 },
1692 }
1693 }
1694
1695 var parentKind = apps.SchemeGroupVersion.WithKind("StatefulSet")
1696
1697 func rawTemplate(template *v1.PodTemplateSpec) runtime.RawExtension {
1698 buf := new(bytes.Buffer)
1699 enc := json.NewEncoder(buf)
1700 if err := enc.Encode(template); err != nil {
1701 panic(err)
1702 }
1703 return runtime.RawExtension{Raw: buf.Bytes()}
1704 }
1705
View as plain text