sigs.k8s.io/cluster-api@v1.6.3/internal/controllers/machineset/machineset_delete_policy_test.go (about) 1 /* 2 Copyright 2018 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 machineset 18 19 import ( 20 "fmt" 21 "testing" 22 23 . "github.com/onsi/gomega" 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/util/rand" 27 28 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 29 capierrors "sigs.k8s.io/cluster-api/errors" 30 ) 31 32 func TestMachineToDelete(t *testing.T) { 33 msg := "something wrong with the machine" 34 now := metav1.Now() 35 nodeRef := &corev1.ObjectReference{Name: "some-node"} 36 healthyMachine := &clusterv1.Machine{Status: clusterv1.MachineStatus{NodeRef: nodeRef}} 37 mustDeleteMachine := &clusterv1.Machine{ 38 ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: &now}, 39 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 40 } 41 betterDeleteMachine := &clusterv1.Machine{ 42 Status: clusterv1.MachineStatus{FailureMessage: &msg, NodeRef: nodeRef}, 43 } 44 deleteMachineWithMachineAnnotation := &clusterv1.Machine{ 45 ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{clusterv1.DeleteMachineAnnotation: ""}}, 46 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 47 } 48 deleteMachineWithoutNodeRef := &clusterv1.Machine{} 49 nodeHealthyConditionFalseMachine := &clusterv1.Machine{ 50 Status: clusterv1.MachineStatus{ 51 NodeRef: nodeRef, 52 Conditions: clusterv1.Conditions{ 53 { 54 Type: clusterv1.MachineNodeHealthyCondition, 55 Status: corev1.ConditionFalse, 56 }, 57 }, 58 }, 59 } 60 nodeHealthyConditionUnknownMachine := &clusterv1.Machine{ 61 Status: clusterv1.MachineStatus{ 62 NodeRef: nodeRef, 63 Conditions: clusterv1.Conditions{ 64 { 65 Type: clusterv1.MachineNodeHealthyCondition, 66 Status: corev1.ConditionUnknown, 67 }, 68 }, 69 }, 70 } 71 72 tests := []struct { 73 desc string 74 machines []*clusterv1.Machine 75 diff int 76 expect []*clusterv1.Machine 77 }{ 78 { 79 desc: "func=randomDeletePolicy, diff=0", 80 diff: 0, 81 machines: []*clusterv1.Machine{ 82 healthyMachine, 83 }, 84 expect: []*clusterv1.Machine{}, 85 }, 86 { 87 desc: "func=randomDeletePolicy, diff>len(machines)", 88 diff: 2, 89 machines: []*clusterv1.Machine{ 90 healthyMachine, 91 }, 92 expect: []*clusterv1.Machine{ 93 healthyMachine, 94 }, 95 }, 96 { 97 desc: "func=randomDeletePolicy, diff>betterDelete", 98 diff: 2, 99 machines: []*clusterv1.Machine{ 100 healthyMachine, 101 betterDeleteMachine, 102 healthyMachine, 103 }, 104 expect: []*clusterv1.Machine{ 105 betterDeleteMachine, 106 healthyMachine, 107 }, 108 }, 109 { 110 desc: "func=randomDeletePolicy, diff<betterDelete", 111 diff: 2, 112 machines: []*clusterv1.Machine{ 113 healthyMachine, 114 betterDeleteMachine, 115 betterDeleteMachine, 116 betterDeleteMachine, 117 }, 118 expect: []*clusterv1.Machine{ 119 betterDeleteMachine, 120 betterDeleteMachine, 121 }, 122 }, 123 { 124 desc: "func=randomDeletePolicy, diff<=mustDelete", 125 diff: 2, 126 machines: []*clusterv1.Machine{ 127 healthyMachine, 128 mustDeleteMachine, 129 betterDeleteMachine, 130 mustDeleteMachine, 131 }, 132 expect: []*clusterv1.Machine{ 133 mustDeleteMachine, 134 mustDeleteMachine, 135 }, 136 }, 137 { 138 desc: "func=randomDeletePolicy, diff<=mustDelete+betterDelete", 139 diff: 2, 140 machines: []*clusterv1.Machine{ 141 healthyMachine, 142 mustDeleteMachine, 143 healthyMachine, 144 betterDeleteMachine, 145 }, 146 expect: []*clusterv1.Machine{ 147 mustDeleteMachine, 148 betterDeleteMachine, 149 }, 150 }, 151 { 152 desc: "func=randomDeletePolicy, diff<=mustDelete+betterDelete+couldDelete", 153 diff: 2, 154 machines: []*clusterv1.Machine{ 155 healthyMachine, 156 mustDeleteMachine, 157 healthyMachine, 158 }, 159 expect: []*clusterv1.Machine{ 160 mustDeleteMachine, 161 healthyMachine, 162 }, 163 }, 164 { 165 desc: "func=randomDeletePolicy, diff>betterDelete", 166 diff: 2, 167 machines: []*clusterv1.Machine{ 168 healthyMachine, 169 betterDeleteMachine, 170 healthyMachine, 171 }, 172 expect: []*clusterv1.Machine{ 173 betterDeleteMachine, 174 healthyMachine, 175 }, 176 }, 177 { 178 desc: "func=randomDeletePolicy, DeleteMachineAnnotation, diff=1", 179 diff: 1, 180 machines: []*clusterv1.Machine{ 181 healthyMachine, 182 deleteMachineWithMachineAnnotation, 183 healthyMachine, 184 }, 185 expect: []*clusterv1.Machine{ 186 deleteMachineWithMachineAnnotation, 187 }, 188 }, 189 { 190 desc: "func=randomDeletePolicy, MachineWithNoNodeRef, diff=1", 191 diff: 1, 192 machines: []*clusterv1.Machine{ 193 healthyMachine, 194 deleteMachineWithoutNodeRef, 195 healthyMachine, 196 }, 197 expect: []*clusterv1.Machine{ 198 deleteMachineWithoutNodeRef, 199 }, 200 }, 201 { 202 desc: "func=randomDeletePolicy, NodeHealthyConditionFalseMachine, diff=1", 203 diff: 1, 204 machines: []*clusterv1.Machine{ 205 healthyMachine, 206 nodeHealthyConditionFalseMachine, 207 healthyMachine, 208 }, 209 expect: []*clusterv1.Machine{ 210 nodeHealthyConditionFalseMachine, 211 }, 212 }, 213 { 214 desc: "func=randomDeletePolicy, NodeHealthyConditionUnknownMachine, diff=1", 215 diff: 1, 216 machines: []*clusterv1.Machine{ 217 healthyMachine, 218 nodeHealthyConditionUnknownMachine, 219 healthyMachine, 220 }, 221 expect: []*clusterv1.Machine{ 222 nodeHealthyConditionUnknownMachine, 223 }, 224 }, 225 } 226 227 for _, test := range tests { 228 t.Run(test.desc, func(t *testing.T) { 229 g := NewWithT(t) 230 231 result := getMachinesToDeletePrioritized(test.machines, test.diff, randomDeletePolicy) 232 g.Expect(result).To(BeComparableTo(test.expect)) 233 }) 234 } 235 } 236 237 func TestMachineNewestDelete(t *testing.T) { 238 currentTime := metav1.Now() 239 statusError := capierrors.MachineStatusError("I'm unhealthy!") 240 nodeRef := &corev1.ObjectReference{Name: "some-node"} 241 mustDeleteMachine := &clusterv1.Machine{ 242 ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: ¤tTime}, 243 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 244 } 245 newest := &clusterv1.Machine{ 246 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -1))}, 247 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 248 } 249 secondNewest := &clusterv1.Machine{ 250 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -5))}, 251 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 252 } 253 secondOldest := &clusterv1.Machine{ 254 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 255 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 256 } 257 oldest := &clusterv1.Machine{ 258 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 259 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 260 } 261 deleteMachineWithMachineAnnotation := &clusterv1.Machine{ 262 ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{clusterv1.DeleteMachineAnnotation: ""}, CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 263 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 264 } 265 unhealthyMachine := &clusterv1.Machine{ 266 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 267 Status: clusterv1.MachineStatus{FailureReason: &statusError, NodeRef: nodeRef}, 268 } 269 deleteMachineWithoutNodeRef := &clusterv1.Machine{ 270 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -1))}, 271 } 272 nodeHealthyConditionFalseMachine := &clusterv1.Machine{ 273 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 274 Status: clusterv1.MachineStatus{ 275 NodeRef: nodeRef, 276 Conditions: clusterv1.Conditions{ 277 { 278 Type: clusterv1.MachineNodeHealthyCondition, 279 Status: corev1.ConditionFalse, 280 }, 281 }, 282 }, 283 } 284 nodeHealthyConditionUnknownMachine := &clusterv1.Machine{ 285 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 286 Status: clusterv1.MachineStatus{ 287 NodeRef: nodeRef, 288 Conditions: clusterv1.Conditions{ 289 { 290 Type: clusterv1.MachineNodeHealthyCondition, 291 Status: corev1.ConditionUnknown, 292 }, 293 }, 294 }, 295 } 296 297 tests := []struct { 298 desc string 299 machines []*clusterv1.Machine 300 diff int 301 expect []*clusterv1.Machine 302 }{ 303 { 304 desc: "func=newestDeletePriority, diff=1", 305 diff: 1, 306 machines: []*clusterv1.Machine{ 307 secondNewest, oldest, secondOldest, mustDeleteMachine, newest, 308 }, 309 expect: []*clusterv1.Machine{mustDeleteMachine}, 310 }, 311 { 312 desc: "func=newestDeletePriority, diff=2", 313 diff: 2, 314 machines: []*clusterv1.Machine{ 315 secondNewest, oldest, mustDeleteMachine, secondOldest, newest, 316 }, 317 expect: []*clusterv1.Machine{mustDeleteMachine, newest}, 318 }, 319 { 320 desc: "func=newestDeletePriority, diff=3", 321 diff: 3, 322 machines: []*clusterv1.Machine{ 323 secondNewest, mustDeleteMachine, oldest, secondOldest, newest, 324 }, 325 expect: []*clusterv1.Machine{mustDeleteMachine, newest, secondNewest}, 326 }, 327 { 328 desc: "func=newestDeletePriority, diff=1 (DeleteMachineAnnotation)", 329 diff: 1, 330 machines: []*clusterv1.Machine{ 331 secondNewest, oldest, secondOldest, newest, deleteMachineWithMachineAnnotation, 332 }, 333 expect: []*clusterv1.Machine{deleteMachineWithMachineAnnotation}, 334 }, 335 { 336 desc: "func=newestDeletePriority, diff=1 (deleteMachineWithoutNodeRef)", 337 diff: 1, 338 machines: []*clusterv1.Machine{ 339 secondNewest, oldest, secondOldest, newest, deleteMachineWithoutNodeRef, 340 }, 341 expect: []*clusterv1.Machine{deleteMachineWithoutNodeRef}, 342 }, 343 { 344 desc: "func=newestDeletePriority, diff=1 (unhealthy)", 345 diff: 1, 346 machines: []*clusterv1.Machine{ 347 secondNewest, oldest, secondOldest, newest, unhealthyMachine, 348 }, 349 expect: []*clusterv1.Machine{unhealthyMachine}, 350 }, 351 { 352 desc: "func=newestDeletePriority, diff=1 (nodeHealthyConditionFalseMachine)", 353 diff: 1, 354 machines: []*clusterv1.Machine{ 355 secondNewest, oldest, secondOldest, newest, nodeHealthyConditionFalseMachine, 356 }, 357 expect: []*clusterv1.Machine{nodeHealthyConditionFalseMachine}, 358 }, 359 { 360 desc: "func=newestDeletePriority, diff=1 (nodeHealthyConditionUnknownMachine)", 361 diff: 1, 362 machines: []*clusterv1.Machine{ 363 secondNewest, oldest, secondOldest, newest, nodeHealthyConditionUnknownMachine, 364 }, 365 expect: []*clusterv1.Machine{nodeHealthyConditionUnknownMachine}, 366 }, 367 } 368 369 for _, test := range tests { 370 t.Run(test.desc, func(t *testing.T) { 371 g := NewWithT(t) 372 373 result := getMachinesToDeletePrioritized(test.machines, test.diff, newestDeletePriority) 374 g.Expect(result).To(BeComparableTo(test.expect)) 375 }) 376 } 377 } 378 379 func TestMachineOldestDelete(t *testing.T) { 380 currentTime := metav1.Now() 381 statusError := capierrors.MachineStatusError("I'm unhealthy!") 382 nodeRef := &corev1.ObjectReference{Name: "some-node"} 383 empty := &clusterv1.Machine{ 384 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 385 } 386 newest := &clusterv1.Machine{ 387 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -1))}, 388 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 389 } 390 secondNewest := &clusterv1.Machine{ 391 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -5))}, 392 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 393 } 394 secondOldest := &clusterv1.Machine{ 395 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 396 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 397 } 398 oldest := &clusterv1.Machine{ 399 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 400 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 401 } 402 deleteMachineWithMachineAnnotation := &clusterv1.Machine{ 403 ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{clusterv1.DeleteMachineAnnotation: ""}, CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 404 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 405 } 406 unhealthyMachine := &clusterv1.Machine{ 407 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 408 Status: clusterv1.MachineStatus{FailureReason: &statusError, NodeRef: nodeRef}, 409 } 410 deleteMachineWithoutNodeRef := &clusterv1.Machine{ 411 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 412 } 413 nodeHealthyConditionFalseMachine := &clusterv1.Machine{ 414 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 415 Status: clusterv1.MachineStatus{ 416 NodeRef: nodeRef, 417 Conditions: clusterv1.Conditions{ 418 { 419 Type: clusterv1.MachineNodeHealthyCondition, 420 Status: corev1.ConditionFalse, 421 }, 422 }, 423 }, 424 } 425 nodeHealthyConditionUnknownMachine := &clusterv1.Machine{ 426 ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.NewTime(currentTime.Time.AddDate(0, 0, -10))}, 427 Status: clusterv1.MachineStatus{ 428 NodeRef: nodeRef, 429 Conditions: clusterv1.Conditions{ 430 { 431 Type: clusterv1.MachineNodeHealthyCondition, 432 Status: corev1.ConditionUnknown, 433 }, 434 }, 435 }, 436 } 437 438 tests := []struct { 439 desc string 440 machines []*clusterv1.Machine 441 diff int 442 expect []*clusterv1.Machine 443 }{ 444 { 445 desc: "func=oldestDeletePriority, diff=1", 446 diff: 1, 447 machines: []*clusterv1.Machine{ 448 empty, secondNewest, oldest, secondOldest, newest, 449 }, 450 expect: []*clusterv1.Machine{oldest}, 451 }, 452 { 453 desc: "func=oldestDeletePriority, diff=2", 454 diff: 2, 455 machines: []*clusterv1.Machine{ 456 secondNewest, oldest, secondOldest, newest, empty, 457 }, 458 expect: []*clusterv1.Machine{oldest, secondOldest}, 459 }, 460 { 461 desc: "func=oldestDeletePriority, diff=3", 462 diff: 3, 463 machines: []*clusterv1.Machine{ 464 secondNewest, oldest, secondOldest, newest, empty, 465 }, 466 expect: []*clusterv1.Machine{oldest, secondOldest, secondNewest}, 467 }, 468 { 469 desc: "func=oldestDeletePriority, diff=4", 470 diff: 4, 471 machines: []*clusterv1.Machine{ 472 secondNewest, oldest, secondOldest, newest, empty, 473 }, 474 expect: []*clusterv1.Machine{oldest, secondOldest, secondNewest, newest}, 475 }, 476 { 477 desc: "func=oldestDeletePriority, diff=1 (DeleteMachineAnnotation)", 478 diff: 1, 479 machines: []*clusterv1.Machine{ 480 empty, secondNewest, oldest, secondOldest, newest, deleteMachineWithMachineAnnotation, 481 }, 482 expect: []*clusterv1.Machine{deleteMachineWithMachineAnnotation}, 483 }, 484 { 485 desc: "func=oldestDeletePriority, diff=1 (deleteMachineWithoutNodeRef)", 486 diff: 1, 487 machines: []*clusterv1.Machine{ 488 empty, secondNewest, oldest, secondOldest, newest, deleteMachineWithoutNodeRef, 489 }, 490 expect: []*clusterv1.Machine{deleteMachineWithoutNodeRef}, 491 }, 492 { 493 desc: "func=oldestDeletePriority, diff=1 (unhealthy)", 494 diff: 1, 495 machines: []*clusterv1.Machine{ 496 empty, secondNewest, oldest, secondOldest, newest, unhealthyMachine, 497 }, 498 expect: []*clusterv1.Machine{unhealthyMachine}, 499 }, 500 { 501 desc: "func=oldestDeletePriority, diff=1 (nodeHealthyConditionFalseMachine)", 502 diff: 1, 503 machines: []*clusterv1.Machine{ 504 empty, secondNewest, oldest, secondOldest, newest, nodeHealthyConditionFalseMachine, 505 }, 506 expect: []*clusterv1.Machine{nodeHealthyConditionFalseMachine}, 507 }, 508 { 509 desc: "func=oldestDeletePriority, diff=1 (nodeHealthyConditionUnknownMachine)", 510 diff: 1, 511 machines: []*clusterv1.Machine{ 512 empty, secondNewest, oldest, secondOldest, newest, nodeHealthyConditionUnknownMachine, 513 }, 514 expect: []*clusterv1.Machine{nodeHealthyConditionUnknownMachine}, 515 }, 516 } 517 518 for _, test := range tests { 519 t.Run(test.desc, func(t *testing.T) { 520 g := NewWithT(t) 521 522 result := getMachinesToDeletePrioritized(test.machines, test.diff, oldestDeletePriority) 523 g.Expect(result).To(BeComparableTo(test.expect)) 524 }) 525 } 526 } 527 528 func TestMachineDeleteMultipleSamePriority(t *testing.T) { 529 machines := make([]*clusterv1.Machine, 0, 10) 530 // All of these machines will have the same delete priority because they all have the "must delete" annotation. 531 for i := 0; i < 10; i++ { 532 machines = append(machines, &clusterv1.Machine{ 533 ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("machine-%d", i), Annotations: map[string]string{clusterv1.DeleteMachineAnnotation: "true"}}, 534 }) 535 } 536 537 tests := []struct { 538 desc string 539 diff int 540 deletePriority deletePriorityFunc 541 }{ 542 { 543 desc: "multiple with same priority, func=oldestDeletePriority, diff=1", 544 diff: 1, 545 deletePriority: oldestDeletePriority, 546 }, 547 { 548 desc: "multiple with same priority, func=oldestDeletePriority, diff=5", 549 diff: 5, 550 deletePriority: oldestDeletePriority, 551 }, 552 { 553 desc: "multiple with same priority, func=oldestDeletePriority, diff=rand", 554 diff: rand.Intn(len(machines)), 555 deletePriority: oldestDeletePriority, 556 }, 557 { 558 desc: "multiple with same priority, func=randomDeletePolicy, diff=1", 559 diff: 1, 560 deletePriority: randomDeletePolicy, 561 }, 562 { 563 desc: "multiple with same priority, func=randomDeletePolicy, diff=5", 564 diff: 5, 565 deletePriority: randomDeletePolicy, 566 }, 567 { 568 desc: "multiple with same priority, func=randomDeletePolicy, diff=rand", 569 diff: rand.Intn(len(machines)), 570 deletePriority: randomDeletePolicy, 571 }, 572 { 573 desc: "multiple with same priority, func=newestDeletePriority, diff=1", 574 diff: 1, 575 deletePriority: newestDeletePriority, 576 }, 577 { 578 desc: "multiple with same priority, func=newestDeletePriority, diff=5", 579 diff: 5, 580 deletePriority: newestDeletePriority, 581 }, 582 { 583 desc: "multiple with same priority, func=newestDeletePriority, diff=rand", 584 diff: rand.Intn(len(machines)), 585 deletePriority: newestDeletePriority, 586 }, 587 { 588 desc: "multiple with same priority, func=randomDeletePolicy, diff=1", 589 diff: 1, 590 deletePriority: randomDeletePolicy, 591 }, 592 { 593 desc: "multiple with same priority, func=randomDeletePolicy, diff=5", 594 diff: 5, 595 deletePriority: randomDeletePolicy, 596 }, 597 { 598 desc: "multiple with same priority, func=randomDeletePolicy, diff=rand", 599 diff: rand.Intn(len(machines)), 600 deletePriority: randomDeletePolicy, 601 }, 602 } 603 604 for _, test := range tests { 605 t.Run(test.desc, func(t *testing.T) { 606 g := NewWithT(t) 607 608 order := rand.Perm(len(machines)) 609 shuffledMachines := make([]*clusterv1.Machine, len(machines)) 610 for i, j := range order { 611 shuffledMachines[i] = machines[j] 612 } 613 614 result := getMachinesToDeletePrioritized(shuffledMachines, test.diff, test.deletePriority) 615 g.Expect(result).To(BeComparableTo(machines[:test.diff])) 616 }) 617 } 618 } 619 620 func TestIsMachineHealthy(t *testing.T) { 621 nodeRef := &corev1.ObjectReference{Name: "some-node"} 622 statusError := capierrors.MachineStatusError("I'm unhealthy!") 623 msg := "something wrong with the machine" 624 625 tests := []struct { 626 desc string 627 machine *clusterv1.Machine 628 expect bool 629 }{ 630 { 631 desc: "when it has no NodeRef", 632 machine: &clusterv1.Machine{}, 633 expect: false, 634 }, 635 { 636 desc: "when it has a FailureReason", 637 machine: &clusterv1.Machine{ 638 Status: clusterv1.MachineStatus{FailureReason: &statusError, NodeRef: nodeRef}, 639 }, 640 expect: false, 641 }, 642 { 643 desc: "when it has a FailureMessage", 644 machine: &clusterv1.Machine{ 645 Status: clusterv1.MachineStatus{FailureMessage: &msg, NodeRef: nodeRef}, 646 }, 647 expect: false, 648 }, 649 { 650 desc: "when nodeHealthyCondition is false", 651 machine: &clusterv1.Machine{ 652 Status: clusterv1.MachineStatus{ 653 NodeRef: nodeRef, 654 Conditions: clusterv1.Conditions{ 655 { 656 Type: clusterv1.MachineNodeHealthyCondition, 657 Status: corev1.ConditionFalse, 658 }, 659 }, 660 }, 661 }, 662 expect: false, 663 }, 664 { 665 desc: "when nodeHealthyCondition is unknown", 666 machine: &clusterv1.Machine{ 667 Status: clusterv1.MachineStatus{ 668 NodeRef: nodeRef, 669 Conditions: clusterv1.Conditions{ 670 { 671 Type: clusterv1.MachineNodeHealthyCondition, 672 Status: corev1.ConditionUnknown, 673 }, 674 }, 675 }, 676 }, 677 expect: false, 678 }, 679 { 680 desc: "when all requirements are met for node to be healthy", 681 machine: &clusterv1.Machine{ 682 Status: clusterv1.MachineStatus{NodeRef: nodeRef}, 683 }, 684 expect: true, 685 }, 686 } 687 688 for _, test := range tests { 689 t.Run(test.desc, func(t *testing.T) { 690 g := NewWithT(t) 691 692 result := isMachineHealthy(test.machine) 693 g.Expect(result).To(Equal(test.expect)) 694 }) 695 } 696 }