k8s.io/kubernetes@v1.29.3/pkg/controller/history/controller_history_test.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package 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 // Clear collisionCount before creating the test revision 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 // Second name collision will be caused by an identical revision, so no need to do anything 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 // Create a new revision with the same name and hash label as an existing revision, but with 309 // a different template. This could happen as a result of a hash collision, but in this test 310 // this situation is created by setting name and hash label to values known to be in use by 311 // an existing revision. 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 // Clear collisionCount before creating the test revision 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 // Second name collision should have incremented collisionCount to 2 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 // Converting all the map-only selectors to set-based selectors. 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 // Purposely leaving MatchLabels nil, so to ensure it will break if any link 1649 // in the chain ignores the set-based MatchExpressions. 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 }