5
5
"fmt"
6
6
"strconv"
7
7
"testing"
8
+ "time"
8
9
9
10
"github.com/civo/civogo"
10
11
corev1 "k8s.io/api/core/v1"
@@ -16,12 +17,13 @@ import (
16
17
)
17
18
18
19
var (
19
- testClusterID = "test-cluster-123"
20
- testRegion = "lon1"
21
- testApiKey = "test-api-key"
22
- testApiURL = "https://test.civo.com"
23
- testNodePoolID = "test-node-pool"
24
- testNodeDesiredGPUCount = "8"
20
+ testClusterID = "test-cluster-123"
21
+ testRegion = "lon1"
22
+ testApiKey = "test-api-key"
23
+ testApiURL = "https://test.civo.com"
24
+ testNodePoolID = "test-node-pool"
25
+ testNodeDesiredGPUCount = "8"
26
+ testRebootTimeWindowMinutes = time .Duration (40 )
25
27
)
26
28
27
29
func TestNew (t * testing.T ) {
@@ -54,6 +56,8 @@ func TestNew(t *testing.T) {
54
56
opts : []Option {
55
57
WithKubernetesClient (fake .NewSimpleClientset ()),
56
58
WithCivoClient (& FakeClient {}),
59
+ WithRebootTimeWindowMinutes ("invalid time" ), // It is invalid, but the default time (40) will be used.
60
+ WithRebootTimeWindowMinutes ("0" ), // It is invalid, but the default time (40) will be used.
57
61
},
58
62
},
59
63
checkFunc : func (w * watcher ) error {
@@ -86,6 +90,9 @@ func TestNew(t *testing.T) {
86
90
if w .civoClient == nil {
87
91
return fmt .Errorf ("civoClient is nil" )
88
92
}
93
+ if w .rebootTimeWindowMinutes != testRebootTimeWindowMinutes {
94
+ return fmt .Errorf ("w.rebootTimeWindowMinutes mismatch: got %v, want %s" , w .nodeSelector , testNodePoolID )
95
+ }
89
96
return nil
90
97
},
91
98
},
@@ -338,6 +345,49 @@ func TestRun(t *testing.T) {
338
345
}
339
346
},
340
347
},
348
+ {
349
+ name : "Returns nil and skips reboot when GPU count matches desired but node is not ready, and LastTransitionTime is more recent than thresholdTime" ,
350
+ args : args {
351
+ opts : []Option {
352
+ WithKubernetesClient (fake .NewSimpleClientset ()),
353
+ WithCivoClient (& FakeClient {}),
354
+ },
355
+ nodeDesiredGPUCount : testNodeDesiredGPUCount ,
356
+ nodePoolID : testNodePoolID ,
357
+ },
358
+ beforeFunc : func (w * watcher ) {
359
+ t .Helper ()
360
+ client := w .client .(* fake.Clientset )
361
+
362
+ nodes := & corev1.NodeList {
363
+ Items : []corev1.Node {
364
+ {
365
+ ObjectMeta : metav1.ObjectMeta {
366
+ Name : "node-01" ,
367
+ Labels : map [string ]string {
368
+ nodePoolLabelKey : testNodePoolID ,
369
+ },
370
+ },
371
+ Status : corev1.NodeStatus {
372
+ Conditions : []corev1.NodeCondition {
373
+ {
374
+ Type : corev1 .NodeReady ,
375
+ Status : corev1 .ConditionFalse ,
376
+ LastTransitionTime : metav1 .NewTime (time .Now ()),
377
+ },
378
+ },
379
+ Allocatable : corev1.ResourceList {
380
+ gpuResourceName : resource .MustParse ("8" ),
381
+ },
382
+ },
383
+ },
384
+ },
385
+ }
386
+ client .Fake .PrependReactor ("list" , "nodes" , func (action k8stesting.Action ) (handled bool , ret runtime.Object , err error ) {
387
+ return true , nodes , nil
388
+ })
389
+ },
390
+ },
341
391
{
342
392
name : "Returns an error when unable to list nodes" ,
343
393
args : args {
@@ -430,6 +480,116 @@ func TestRun(t *testing.T) {
430
480
}
431
481
}
432
482
483
+ func TestIsReadyOrNotReadyStatusChangedAfter (t * testing.T ) {
484
+ type test struct {
485
+ name string
486
+ node * corev1.Node
487
+ thresholdTime time.Time
488
+ want bool
489
+ }
490
+
491
+ tests := []test {
492
+ {
493
+ name : "Returns true when NodeReady condition is true (Ready) and last transition time is after threshold" ,
494
+ node : & corev1.Node {
495
+ ObjectMeta : metav1.ObjectMeta {
496
+ Name : "node-01" ,
497
+ },
498
+ Status : corev1.NodeStatus {
499
+ Conditions : []corev1.NodeCondition {
500
+ {
501
+ Type : corev1 .NodeReady ,
502
+ Status : corev1 .ConditionTrue ,
503
+ LastTransitionTime : metav1 .NewTime (time .Now ()),
504
+ },
505
+ },
506
+ },
507
+ },
508
+ thresholdTime : time .Now ().Add (- time .Hour ),
509
+ want : true ,
510
+ },
511
+ {
512
+ name : "Returns true when NodeReady condition is false (NotReady) and last transition time is after threshold" ,
513
+ node : & corev1.Node {
514
+ ObjectMeta : metav1.ObjectMeta {
515
+ Name : "node-01" ,
516
+ },
517
+ Status : corev1.NodeStatus {
518
+ Conditions : []corev1.NodeCondition {
519
+ {
520
+ Type : corev1 .NodeReady ,
521
+ Status : corev1 .ConditionFalse ,
522
+ LastTransitionTime : metav1 .NewTime (time .Now ()),
523
+ },
524
+ },
525
+ },
526
+ },
527
+ thresholdTime : time .Now ().Add (- time .Hour ),
528
+ want : true ,
529
+ },
530
+ {
531
+ name : "Returns false when the latest NodeReady condition is older than thresholdTime" ,
532
+ node : & corev1.Node {
533
+ ObjectMeta : metav1.ObjectMeta {
534
+ Name : "node-01" ,
535
+ },
536
+ Status : corev1.NodeStatus {
537
+ Conditions : []corev1.NodeCondition {
538
+ {
539
+ Type : corev1 .NodeReady ,
540
+ Status : corev1 .ConditionFalse ,
541
+ LastTransitionTime : metav1 .NewTime (time .Now ().Add (- time .Hour )),
542
+ },
543
+ },
544
+ },
545
+ },
546
+ thresholdTime : time .Now (),
547
+ want : false ,
548
+ },
549
+ {
550
+ name : "Returns false when no conditions are present on the node" ,
551
+ node : & corev1.Node {
552
+ ObjectMeta : metav1.ObjectMeta {
553
+ Name : "node-01" ,
554
+ },
555
+ Status : corev1.NodeStatus {
556
+ Conditions : []corev1.NodeCondition {},
557
+ },
558
+ },
559
+ thresholdTime : time .Now ().Add (- time .Hour ),
560
+ want : false ,
561
+ },
562
+ {
563
+ name : "Returns false when there is only NodeDiskPressure condition" ,
564
+ node : & corev1.Node {
565
+ ObjectMeta : metav1.ObjectMeta {
566
+ Name : "node-01" ,
567
+ },
568
+ Status : corev1.NodeStatus {
569
+ Conditions : []corev1.NodeCondition {
570
+ {
571
+ Type : corev1 .NodeDiskPressure ,
572
+ Status : corev1 .ConditionFalse ,
573
+ LastHeartbeatTime : metav1 .NewTime (time .Now ()),
574
+ },
575
+ },
576
+ },
577
+ },
578
+ thresholdTime : time .Now ().Add (- time .Hour ),
579
+ want : false ,
580
+ },
581
+ }
582
+
583
+ for _ , test := range tests {
584
+ t .Run (test .name , func (t * testing.T ) {
585
+ got := isReadyOrNotReadyStatusChangedAfter (test .node , test .thresholdTime )
586
+ if got != test .want {
587
+ t .Errorf ("got = %v, want %v" , got , test .want )
588
+ }
589
+ })
590
+ }
591
+ }
592
+
433
593
func TestIsNodeReady (t * testing.T ) {
434
594
type test struct {
435
595
name string
0 commit comments