k8s.io/kubernetes@v1.29.3/pkg/util/taints/taints_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 taints 18 19 import ( 20 "reflect" 21 "strings" 22 "testing" 23 24 v1 "k8s.io/api/core/v1" 25 26 "github.com/google/go-cmp/cmp" 27 ) 28 29 func TestAddOrUpdateTaint(t *testing.T) { 30 taint := v1.Taint{ 31 Key: "foo", 32 Value: "bar", 33 Effect: v1.TaintEffectNoSchedule, 34 } 35 36 taintNew := v1.Taint{ 37 Key: "foo_1", 38 Value: "bar_1", 39 Effect: v1.TaintEffectNoSchedule, 40 } 41 42 taintUpdateValue := taint 43 taintUpdateValue.Value = "bar_1" 44 45 testcases := []struct { 46 name string 47 node *v1.Node 48 taint *v1.Taint 49 expectedUpdate bool 50 expectedTaints []v1.Taint 51 }{ 52 { 53 name: "add a new taint", 54 node: &v1.Node{}, 55 taint: &taint, 56 expectedUpdate: true, 57 expectedTaints: []v1.Taint{taint}, 58 }, 59 { 60 name: "add a unique taint", 61 node: &v1.Node{ 62 Spec: v1.NodeSpec{Taints: []v1.Taint{taint}}, 63 }, 64 taint: &taintNew, 65 expectedUpdate: true, 66 expectedTaints: []v1.Taint{taint, taintNew}, 67 }, 68 { 69 name: "add duplicate taint", 70 node: &v1.Node{ 71 Spec: v1.NodeSpec{Taints: []v1.Taint{taint}}, 72 }, 73 taint: &taint, 74 expectedUpdate: false, 75 expectedTaints: []v1.Taint{taint}, 76 }, 77 { 78 name: "update taint value", 79 node: &v1.Node{ 80 Spec: v1.NodeSpec{Taints: []v1.Taint{taint}}, 81 }, 82 taint: &taintUpdateValue, 83 expectedUpdate: true, 84 expectedTaints: []v1.Taint{taintUpdateValue}, 85 }, 86 } 87 88 for _, tc := range testcases { 89 t.Run(tc.name, func(t *testing.T) { 90 newNode, updated, err := AddOrUpdateTaint(tc.node, tc.taint) 91 if err != nil { 92 t.Errorf("[%s] should not raise error but got %v", tc.name, err) 93 } 94 if updated != tc.expectedUpdate { 95 t.Errorf("[%s] expected taints to not be updated", tc.name) 96 } 97 if diff := cmp.Diff(newNode.Spec.Taints, tc.expectedTaints); diff != "" { 98 t.Errorf("Unexpected result (-want, +got):\n%s", diff) 99 } 100 }) 101 } 102 } 103 104 func TestTaintExists(t *testing.T) { 105 testingTaints := []v1.Taint{ 106 { 107 Key: "foo_1", 108 Value: "bar_1", 109 Effect: v1.TaintEffectNoExecute, 110 }, 111 { 112 Key: "foo_2", 113 Value: "bar_2", 114 Effect: v1.TaintEffectNoSchedule, 115 }, 116 } 117 118 cases := []struct { 119 name string 120 taintToFind *v1.Taint 121 expectedResult bool 122 }{ 123 { 124 name: "taint exists", 125 taintToFind: &v1.Taint{Key: "foo_1", Value: "bar_1", Effect: v1.TaintEffectNoExecute}, 126 expectedResult: true, 127 }, 128 { 129 name: "different key", 130 taintToFind: &v1.Taint{Key: "no_such_key", Value: "bar_1", Effect: v1.TaintEffectNoExecute}, 131 expectedResult: false, 132 }, 133 { 134 name: "different effect", 135 taintToFind: &v1.Taint{Key: "foo_1", Value: "bar_1", Effect: v1.TaintEffectNoSchedule}, 136 expectedResult: false, 137 }, 138 } 139 140 for _, c := range cases { 141 result := TaintExists(testingTaints, c.taintToFind) 142 143 if result != c.expectedResult { 144 t.Errorf("[%s] unexpected results: %v", c.name, result) 145 continue 146 } 147 } 148 } 149 150 func TestTaintKeyExists(t *testing.T) { 151 testingTaints := []v1.Taint{ 152 { 153 Key: "foo_1", 154 Value: "bar_1", 155 Effect: v1.TaintEffectNoExecute, 156 }, 157 { 158 Key: "foo_2", 159 Value: "bar_2", 160 Effect: v1.TaintEffectNoSchedule, 161 }, 162 } 163 164 cases := []struct { 165 name string 166 taintKeyToMatch string 167 expectedResult bool 168 }{ 169 { 170 name: "taint key exists", 171 taintKeyToMatch: "foo_1", 172 expectedResult: true, 173 }, 174 { 175 name: "taint key does not exist", 176 taintKeyToMatch: "foo_3", 177 expectedResult: false, 178 }, 179 } 180 181 for _, c := range cases { 182 t.Run(c.name, func(t *testing.T) { 183 result := TaintKeyExists(testingTaints, c.taintKeyToMatch) 184 185 if result != c.expectedResult { 186 t.Errorf("[%s] unexpected results: %v", c.name, result) 187 } 188 }) 189 } 190 } 191 192 func TestTaintSetFilter(t *testing.T) { 193 testTaint1 := v1.Taint{ 194 Key: "foo_1", 195 Value: "bar_1", 196 Effect: v1.TaintEffectNoExecute, 197 } 198 testTaint2 := v1.Taint{ 199 Key: "foo_2", 200 Value: "bar_2", 201 Effect: v1.TaintEffectNoSchedule, 202 } 203 204 testTaint3 := v1.Taint{ 205 Key: "foo_3", 206 Value: "bar_3", 207 Effect: v1.TaintEffectNoSchedule, 208 } 209 testTaints := []v1.Taint{testTaint1, testTaint2, testTaint3} 210 211 testcases := []struct { 212 name string 213 fn func(t *v1.Taint) bool 214 expectedTaints []v1.Taint 215 }{ 216 { 217 name: "Filter out nothing", 218 fn: func(t *v1.Taint) bool { 219 if t.Key == v1.TaintNodeUnschedulable { 220 return true 221 } 222 return false 223 }, 224 expectedTaints: []v1.Taint{}, 225 }, 226 { 227 name: "Filter out a subset", 228 fn: func(t *v1.Taint) bool { 229 if t.Effect == v1.TaintEffectNoExecute { 230 return true 231 } 232 return false 233 }, 234 expectedTaints: []v1.Taint{testTaint1}, 235 }, 236 { 237 name: "Filter out everything", 238 fn: func(t *v1.Taint) bool { return true }, 239 expectedTaints: []v1.Taint{testTaint1, testTaint2, testTaint3}, 240 }, 241 } 242 for _, tc := range testcases { 243 t.Run(tc.name, func(t *testing.T) { 244 taintsAfterFilter := TaintSetFilter(testTaints, tc.fn) 245 if diff := cmp.Diff(tc.expectedTaints, taintsAfterFilter); diff != "" { 246 t.Errorf("Unexpected postFilterResult (-want, +got):\n%s", diff) 247 } 248 }) 249 } 250 } 251 252 func TestRemoveTaint(t *testing.T) { 253 cases := []struct { 254 name string 255 node *v1.Node 256 taintToRemove *v1.Taint 257 expectedTaints []v1.Taint 258 expectedResult bool 259 }{ 260 { 261 name: "remove taint unsuccessfully", 262 node: &v1.Node{ 263 Spec: v1.NodeSpec{ 264 Taints: []v1.Taint{ 265 { 266 Key: "foo", 267 Effect: v1.TaintEffectNoSchedule, 268 }, 269 }, 270 }, 271 }, 272 taintToRemove: &v1.Taint{ 273 Key: "foo_1", 274 Effect: v1.TaintEffectNoSchedule, 275 }, 276 expectedTaints: []v1.Taint{ 277 { 278 Key: "foo", 279 Effect: v1.TaintEffectNoSchedule, 280 }, 281 }, 282 expectedResult: false, 283 }, 284 { 285 name: "remove taint successfully", 286 node: &v1.Node{ 287 Spec: v1.NodeSpec{ 288 Taints: []v1.Taint{ 289 { 290 Key: "foo", 291 Effect: v1.TaintEffectNoSchedule, 292 }, 293 }, 294 }, 295 }, 296 taintToRemove: &v1.Taint{ 297 Key: "foo", 298 Effect: v1.TaintEffectNoSchedule, 299 }, 300 expectedTaints: []v1.Taint{}, 301 expectedResult: true, 302 }, 303 { 304 name: "remove taint from node with no taint", 305 node: &v1.Node{ 306 Spec: v1.NodeSpec{ 307 Taints: []v1.Taint{}, 308 }, 309 }, 310 taintToRemove: &v1.Taint{ 311 Key: "foo", 312 Effect: v1.TaintEffectNoSchedule, 313 }, 314 expectedTaints: []v1.Taint{}, 315 expectedResult: false, 316 }, 317 } 318 319 for _, c := range cases { 320 newNode, result, err := RemoveTaint(c.node, c.taintToRemove) 321 if err != nil { 322 t.Errorf("[%s] should not raise error but got: %v", c.name, err) 323 } 324 if result != c.expectedResult { 325 t.Errorf("[%s] should return %t, but got: %t", c.name, c.expectedResult, result) 326 } 327 if !reflect.DeepEqual(newNode.Spec.Taints, c.expectedTaints) { 328 t.Errorf("[%s] the new node object should have taints %v, but got: %v", c.name, c.expectedTaints, newNode.Spec.Taints) 329 } 330 } 331 } 332 333 func TestDeleteTaint(t *testing.T) { 334 cases := []struct { 335 name string 336 taints []v1.Taint 337 taintToDelete *v1.Taint 338 expectedTaints []v1.Taint 339 expectedResult bool 340 }{ 341 { 342 name: "delete taint with different name", 343 taints: []v1.Taint{ 344 { 345 Key: "foo", 346 Effect: v1.TaintEffectNoSchedule, 347 }, 348 }, 349 taintToDelete: &v1.Taint{Key: "foo_1", Effect: v1.TaintEffectNoSchedule}, 350 expectedTaints: []v1.Taint{ 351 { 352 Key: "foo", 353 Effect: v1.TaintEffectNoSchedule, 354 }, 355 }, 356 expectedResult: false, 357 }, 358 { 359 name: "delete taint with different effect", 360 taints: []v1.Taint{ 361 { 362 Key: "foo", 363 Effect: v1.TaintEffectNoSchedule, 364 }, 365 }, 366 taintToDelete: &v1.Taint{Key: "foo", Effect: v1.TaintEffectNoExecute}, 367 expectedTaints: []v1.Taint{ 368 { 369 Key: "foo", 370 Effect: v1.TaintEffectNoSchedule, 371 }, 372 }, 373 expectedResult: false, 374 }, 375 { 376 name: "delete taint successfully", 377 taints: []v1.Taint{ 378 { 379 Key: "foo", 380 Effect: v1.TaintEffectNoSchedule, 381 }, 382 }, 383 taintToDelete: &v1.Taint{Key: "foo", Effect: v1.TaintEffectNoSchedule}, 384 expectedTaints: []v1.Taint{}, 385 expectedResult: true, 386 }, 387 { 388 name: "delete taint from empty taint array", 389 taints: []v1.Taint{}, 390 taintToDelete: &v1.Taint{Key: "foo", Effect: v1.TaintEffectNoSchedule}, 391 expectedTaints: []v1.Taint{}, 392 expectedResult: false, 393 }, 394 } 395 396 for _, c := range cases { 397 taints, result := DeleteTaint(c.taints, c.taintToDelete) 398 if result != c.expectedResult { 399 t.Errorf("[%s] should return %t, but got: %t", c.name, c.expectedResult, result) 400 } 401 if !reflect.DeepEqual(taints, c.expectedTaints) { 402 t.Errorf("[%s] the result taints should be %v, but got: %v", c.name, c.expectedTaints, taints) 403 } 404 } 405 } 406 407 func TestDeleteTaintByKey(t *testing.T) { 408 cases := []struct { 409 name string 410 taints []v1.Taint 411 taintKey string 412 expectedTaints []v1.Taint 413 expectedResult bool 414 }{ 415 { 416 name: "delete taint unsuccessfully", 417 taints: []v1.Taint{ 418 { 419 Key: "foo", 420 Value: "bar", 421 Effect: v1.TaintEffectNoSchedule, 422 }, 423 }, 424 taintKey: "foo_1", 425 expectedTaints: []v1.Taint{ 426 { 427 Key: "foo", 428 Value: "bar", 429 Effect: v1.TaintEffectNoSchedule, 430 }, 431 }, 432 expectedResult: false, 433 }, 434 { 435 name: "delete taint successfully", 436 taints: []v1.Taint{ 437 { 438 Key: "foo", 439 Value: "bar", 440 Effect: v1.TaintEffectNoSchedule, 441 }, 442 }, 443 taintKey: "foo", 444 expectedTaints: []v1.Taint{}, 445 expectedResult: true, 446 }, 447 { 448 name: "delete taint from empty taint array", 449 taints: []v1.Taint{}, 450 taintKey: "foo", 451 expectedTaints: []v1.Taint{}, 452 expectedResult: false, 453 }, 454 } 455 456 for _, c := range cases { 457 taints, result := DeleteTaintsByKey(c.taints, c.taintKey) 458 if result != c.expectedResult { 459 t.Errorf("[%s] should return %t, but got: %t", c.name, c.expectedResult, result) 460 } 461 if !reflect.DeepEqual(c.expectedTaints, taints) { 462 t.Errorf("[%s] the result taints should be %v, but got: %v", c.name, c.expectedTaints, taints) 463 } 464 } 465 } 466 467 func TestCheckIfTaintsAlreadyExists(t *testing.T) { 468 oldTaints := []v1.Taint{ 469 { 470 Key: "foo_1", 471 Value: "bar", 472 Effect: v1.TaintEffectNoSchedule, 473 }, 474 { 475 Key: "foo_2", 476 Value: "bar", 477 Effect: v1.TaintEffectNoSchedule, 478 }, 479 { 480 Key: "foo_3", 481 Value: "bar", 482 Effect: v1.TaintEffectNoSchedule, 483 }, 484 } 485 486 cases := []struct { 487 name string 488 taintsToCheck []v1.Taint 489 expectedResult string 490 }{ 491 { 492 name: "empty array", 493 taintsToCheck: []v1.Taint{}, 494 expectedResult: "", 495 }, 496 { 497 name: "no match", 498 taintsToCheck: []v1.Taint{ 499 { 500 Key: "foo_1", 501 Effect: v1.TaintEffectNoExecute, 502 }, 503 }, 504 expectedResult: "", 505 }, 506 { 507 name: "match one taint", 508 taintsToCheck: []v1.Taint{ 509 { 510 Key: "foo_2", 511 Effect: v1.TaintEffectNoSchedule, 512 }, 513 }, 514 expectedResult: "foo_2", 515 }, 516 { 517 name: "match two taints", 518 taintsToCheck: []v1.Taint{ 519 { 520 Key: "foo_2", 521 Effect: v1.TaintEffectNoSchedule, 522 }, 523 { 524 Key: "foo_3", 525 Effect: v1.TaintEffectNoSchedule, 526 }, 527 }, 528 expectedResult: "foo_2,foo_3", 529 }, 530 } 531 532 for _, c := range cases { 533 result := CheckIfTaintsAlreadyExists(oldTaints, c.taintsToCheck) 534 if result != c.expectedResult { 535 t.Errorf("[%s] should return '%s', but got: '%s'", c.name, c.expectedResult, result) 536 } 537 } 538 } 539 540 func TestParseTaints(t *testing.T) { 541 cases := []struct { 542 name string 543 spec []string 544 expectedTaints []v1.Taint 545 expectedTaintsToRemove []v1.Taint 546 expectedErr bool 547 }{ 548 { 549 name: "invalid empty spec format", 550 spec: []string{""}, 551 expectedErr: true, 552 }, 553 // taint spec format without the suffix '-' must be either '<key>=<value>:<effect>', '<key>:<effect>', or '<key>' 554 { 555 name: "invalid spec format without effect", 556 spec: []string{"foo=abc"}, 557 expectedErr: true, 558 }, 559 { 560 name: "invalid spec format with multiple '=' separators", 561 spec: []string{"foo=abc=xyz:NoSchedule"}, 562 expectedErr: true, 563 }, 564 { 565 name: "invalid spec format with multiple ':' separators", 566 spec: []string{"foo=abc:xyz:NoSchedule"}, 567 expectedErr: true, 568 }, 569 { 570 name: "invalid spec taint value without separator", 571 spec: []string{"foo"}, 572 expectedErr: true, 573 }, 574 // taint spec must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character. 575 { 576 name: "invalid spec taint value with special chars '%^@'", 577 spec: []string{"foo=nospecialchars%^@:NoSchedule"}, 578 expectedErr: true, 579 }, 580 { 581 name: "invalid spec taint value with non-alphanumeric characters", 582 spec: []string{"foo=Tama-nui-te-rā.is.Māori.sun:NoSchedule"}, 583 expectedErr: true, 584 }, 585 { 586 name: "invalid spec taint value with special chars '\\'", 587 spec: []string{"foo=\\backslashes\\are\\bad:NoSchedule"}, 588 expectedErr: true, 589 }, 590 { 591 name: "invalid spec taint value with start with an non-alphanumeric character '-'", 592 spec: []string{"foo=-starts-with-dash:NoSchedule"}, 593 expectedErr: true, 594 }, 595 { 596 name: "invalid spec taint value with end with an non-alphanumeric character '-'", 597 spec: []string{"foo=ends-with-dash-:NoSchedule"}, 598 expectedErr: true, 599 }, 600 { 601 name: "invalid spec taint value with start with an non-alphanumeric character '.'", 602 spec: []string{"foo=.starts.with.dot:NoSchedule"}, 603 expectedErr: true, 604 }, 605 { 606 name: "invalid spec taint value with end with an non-alphanumeric character '.'", 607 spec: []string{"foo=ends.with.dot.:NoSchedule"}, 608 expectedErr: true, 609 }, 610 // The value range of taint effect is "NoSchedule", "PreferNoSchedule", "NoExecute" 611 { 612 name: "invalid spec effect for adding taint", 613 spec: []string{"foo=abc:invalid_effect"}, 614 expectedErr: true, 615 }, 616 { 617 name: "invalid spec effect for deleting taint", 618 spec: []string{"foo:invalid_effect-"}, 619 expectedErr: true, 620 }, 621 { 622 name: "duplicated taints with the same key and effect", 623 spec: []string{"foo=abc:NoSchedule", "foo=abc:NoSchedule"}, 624 expectedErr: true, 625 }, 626 { 627 name: "invalid spec taint value exceeding the limit", 628 spec: []string{strings.Repeat("a", 64)}, 629 expectedErr: true, 630 }, 631 { 632 name: "add new taints with no special chars", 633 spec: []string{"foo=abc:NoSchedule", "bar=abc:NoSchedule", "baz:NoSchedule", "qux:NoSchedule", "foobar=:NoSchedule"}, 634 expectedTaints: []v1.Taint{ 635 { 636 Key: "foo", 637 Value: "abc", 638 Effect: v1.TaintEffectNoSchedule, 639 }, 640 { 641 Key: "bar", 642 Value: "abc", 643 Effect: v1.TaintEffectNoSchedule, 644 }, 645 { 646 Key: "baz", 647 Value: "", 648 Effect: v1.TaintEffectNoSchedule, 649 }, 650 { 651 Key: "qux", 652 Value: "", 653 Effect: v1.TaintEffectNoSchedule, 654 }, 655 { 656 Key: "foobar", 657 Value: "", 658 Effect: v1.TaintEffectNoSchedule, 659 }, 660 }, 661 expectedErr: false, 662 }, 663 { 664 name: "delete taints with no special chars", 665 spec: []string{"foo:NoSchedule-", "bar:NoSchedule-", "qux=:NoSchedule-", "dedicated-"}, 666 expectedTaintsToRemove: []v1.Taint{ 667 { 668 Key: "foo", 669 Effect: v1.TaintEffectNoSchedule, 670 }, 671 { 672 Key: "bar", 673 Effect: v1.TaintEffectNoSchedule, 674 }, 675 { 676 Key: "qux", 677 Effect: v1.TaintEffectNoSchedule, 678 }, 679 { 680 Key: "dedicated", 681 }, 682 }, 683 expectedErr: false, 684 }, 685 { 686 name: "add taints and delete taints with no special chars", 687 spec: []string{"foo=abc:NoSchedule", "bar=abc:NoSchedule", "baz:NoSchedule", "qux:NoSchedule", "foobar=:NoSchedule", "foo:NoSchedule-", "bar:NoSchedule-", "baz=:NoSchedule-"}, 688 expectedTaints: []v1.Taint{ 689 { 690 Key: "foo", 691 Value: "abc", 692 Effect: v1.TaintEffectNoSchedule, 693 }, 694 { 695 Key: "bar", 696 Value: "abc", 697 Effect: v1.TaintEffectNoSchedule, 698 }, 699 { 700 Key: "baz", 701 Value: "", 702 Effect: v1.TaintEffectNoSchedule, 703 }, 704 { 705 Key: "qux", 706 Value: "", 707 Effect: v1.TaintEffectNoSchedule, 708 }, 709 { 710 Key: "foobar", 711 Value: "", 712 Effect: v1.TaintEffectNoSchedule, 713 }, 714 }, 715 expectedTaintsToRemove: []v1.Taint{ 716 { 717 Key: "foo", 718 Effect: v1.TaintEffectNoSchedule, 719 }, 720 { 721 Key: "bar", 722 Effect: v1.TaintEffectNoSchedule, 723 }, 724 { 725 Key: "baz", 726 Value: "", 727 Effect: v1.TaintEffectNoSchedule, 728 }, 729 }, 730 expectedErr: false, 731 }, 732 } 733 734 for _, c := range cases { 735 taints, taintsToRemove, err := ParseTaints(c.spec) 736 if c.expectedErr && err == nil { 737 t.Errorf("[%s] expected error for spec %s, but got nothing", c.name, c.spec) 738 } 739 if !c.expectedErr && err != nil { 740 t.Errorf("[%s] expected no error for spec %s, but got: %v", c.name, c.spec, err) 741 } 742 if !reflect.DeepEqual(c.expectedTaints, taints) { 743 t.Errorf("[%s] expected returen taints as %v, but got: %v", c.name, c.expectedTaints, taints) 744 } 745 if !reflect.DeepEqual(c.expectedTaintsToRemove, taintsToRemove) { 746 t.Errorf("[%s] expected return taints to be removed as %v, but got: %v", c.name, c.expectedTaintsToRemove, taintsToRemove) 747 } 748 } 749 } 750 751 func TestValidateTaint(t *testing.T) { 752 cases := []struct { 753 name string 754 taintsToCheck v1.Taint 755 expectedErr bool 756 }{ 757 { 758 name: "taint invalid key", 759 taintsToCheck: v1.Taint{Key: "", Value: "bar_1", Effect: v1.TaintEffectNoExecute}, 760 expectedErr: true, 761 }, 762 { 763 name: "taint invalid value", 764 taintsToCheck: v1.Taint{Key: "foo_1", Value: strings.Repeat("a", 64), Effect: v1.TaintEffectNoExecute}, 765 expectedErr: true, 766 }, 767 { 768 name: "taint invalid effect", 769 taintsToCheck: v1.Taint{Key: "foo_2", Value: "bar_2", Effect: "no_such_effect"}, 770 expectedErr: true, 771 }, 772 { 773 name: "valid taint", 774 taintsToCheck: v1.Taint{Key: "foo_3", Value: "bar_3", Effect: v1.TaintEffectNoExecute}, 775 expectedErr: false, 776 }, 777 { 778 name: "valid taint", 779 taintsToCheck: v1.Taint{Key: "foo_4", Effect: v1.TaintEffectNoExecute}, 780 expectedErr: false, 781 }, 782 { 783 name: "valid taint", 784 taintsToCheck: v1.Taint{Key: "foo_5", Value: "bar_5"}, 785 expectedErr: false, 786 }, 787 } 788 789 for _, c := range cases { 790 err := CheckTaintValidation(c.taintsToCheck) 791 792 if c.expectedErr && err == nil { 793 t.Errorf("[%s] expected error for spec %+v, but got nothing", c.name, c.taintsToCheck) 794 } 795 } 796 } 797 798 func TestTaintSetDiff(t *testing.T) { 799 cases := []struct { 800 name string 801 t1 []v1.Taint 802 t2 []v1.Taint 803 expectedTaintsToAdd []*v1.Taint 804 expectedTaintsToRemove []*v1.Taint 805 }{ 806 { 807 name: "two_taints_are_nil", 808 expectedTaintsToAdd: nil, 809 expectedTaintsToRemove: nil, 810 }, 811 { 812 name: "one_taint_is_nil_and_the_other_is_not_nil", 813 t1: []v1.Taint{ 814 { 815 Key: "foo_1", 816 Value: "bar_1", 817 Effect: v1.TaintEffectNoExecute, 818 }, 819 { 820 Key: "foo_2", 821 Value: "bar_2", 822 Effect: v1.TaintEffectNoSchedule, 823 }, 824 }, 825 expectedTaintsToAdd: []*v1.Taint{ 826 { 827 Key: "foo_1", 828 Value: "bar_1", 829 Effect: v1.TaintEffectNoExecute, 830 }, 831 { 832 Key: "foo_2", 833 Value: "bar_2", 834 Effect: v1.TaintEffectNoSchedule, 835 }, 836 }, 837 expectedTaintsToRemove: nil, 838 }, 839 { 840 name: "shared_taints_with_the_same_key_value_effect", 841 t1: []v1.Taint{ 842 { 843 Key: "foo_1", 844 Value: "bar_1", 845 Effect: v1.TaintEffectNoExecute, 846 }, 847 { 848 Key: "foo_2", 849 Value: "bar_2", 850 Effect: v1.TaintEffectNoSchedule, 851 }, 852 }, 853 t2: []v1.Taint{ 854 { 855 Key: "foo_3", 856 Value: "bar_3", 857 Effect: v1.TaintEffectNoExecute, 858 }, 859 { 860 Key: "foo_2", 861 Value: "bar_2", 862 Effect: v1.TaintEffectNoSchedule, 863 }, 864 }, 865 expectedTaintsToAdd: []*v1.Taint{ 866 { 867 Key: "foo_1", 868 Value: "bar_1", 869 Effect: v1.TaintEffectNoExecute, 870 }, 871 }, 872 expectedTaintsToRemove: []*v1.Taint{ 873 { 874 Key: "foo_3", 875 Value: "bar_3", 876 Effect: v1.TaintEffectNoExecute, 877 }, 878 }, 879 }, 880 { 881 name: "shared_taints_with_the_same_key_effect_different_value", 882 t1: []v1.Taint{ 883 { 884 Key: "foo_1", 885 Value: "bar_1", 886 Effect: v1.TaintEffectNoExecute, 887 }, 888 { 889 Key: "foo_2", 890 Value: "different-value", 891 Effect: v1.TaintEffectNoSchedule, 892 }, 893 }, 894 t2: []v1.Taint{ 895 { 896 Key: "foo_3", 897 Value: "bar_3", 898 Effect: v1.TaintEffectNoExecute, 899 }, 900 { 901 Key: "foo_2", 902 Value: "bar_2", 903 Effect: v1.TaintEffectNoSchedule, 904 }, 905 }, 906 expectedTaintsToAdd: []*v1.Taint{ 907 { 908 Key: "foo_1", 909 Value: "bar_1", 910 Effect: v1.TaintEffectNoExecute, 911 }, 912 }, 913 expectedTaintsToRemove: []*v1.Taint{ 914 { 915 Key: "foo_3", 916 Value: "bar_3", 917 Effect: v1.TaintEffectNoExecute, 918 }, 919 }, 920 }, 921 { 922 name: "shared_taints_with_the_same_key_different_value_effect", 923 t1: []v1.Taint{ 924 { 925 Key: "foo_1", 926 Value: "bar_1", 927 Effect: v1.TaintEffectNoExecute, 928 }, 929 { 930 Key: "foo_2", 931 Value: "different-value", 932 Effect: v1.TaintEffectNoExecute, 933 }, 934 }, 935 t2: []v1.Taint{ 936 { 937 Key: "foo_3", 938 Value: "bar_3", 939 Effect: v1.TaintEffectNoExecute, 940 }, 941 { 942 Key: "foo_2", 943 Value: "bar_2", 944 Effect: v1.TaintEffectNoSchedule, 945 }, 946 }, 947 expectedTaintsToAdd: []*v1.Taint{ 948 { 949 Key: "foo_1", 950 Value: "bar_1", 951 Effect: v1.TaintEffectNoExecute, 952 }, 953 { 954 Key: "foo_2", 955 Value: "different-value", 956 Effect: v1.TaintEffectNoExecute, 957 }, 958 }, 959 expectedTaintsToRemove: []*v1.Taint{ 960 { 961 Key: "foo_3", 962 Value: "bar_3", 963 Effect: v1.TaintEffectNoExecute, 964 }, 965 { 966 Key: "foo_2", 967 Value: "bar_2", 968 Effect: v1.TaintEffectNoSchedule, 969 }, 970 }, 971 }, 972 } 973 974 for _, tt := range cases { 975 t.Run(tt.name, func(t *testing.T) { 976 add, remove := TaintSetDiff(tt.t1, tt.t2) 977 if !reflect.DeepEqual(add, tt.expectedTaintsToAdd) { 978 t.Errorf("taintsToAdd: %v should equal %v, but get unexpected results", add, tt.expectedTaintsToAdd) 979 } 980 if !reflect.DeepEqual(remove, tt.expectedTaintsToRemove) { 981 t.Errorf("taintsToRemove: %v should equal %v, but get unexpected results", remove, tt.expectedTaintsToRemove) 982 } 983 }) 984 } 985 }