@@ -20,6 +20,7 @@ import (
20
20
"context"
21
21
"reflect"
22
22
"testing"
23
+ "time"
23
24
24
25
corev1 "k8s.io/api/core/v1"
25
26
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -537,3 +538,303 @@ func TestNoExecuteTaintManager_syncClusterBindingEviction(t *testing.T) {
537
538
})
538
539
}
539
540
}
541
+
542
+ func TestNoExecuteTaintManager_needEviction (t * testing.T ) {
543
+ now := time .Now ()
544
+ oneSecondAgo := metav1.Time {Time : now .Add (- 1 * time .Second )}
545
+ oneSecondLater := metav1.Time {Time : now .Add (1 * time .Second )}
546
+
547
+ // Test cases
548
+ tests := []struct {
549
+ name string
550
+ clusterName string
551
+ annotations map [string ]string
552
+ cluster * clusterv1alpha1.Cluster
553
+ enableNoExecuteTaintEviction bool
554
+ expectedNeedEviction bool
555
+ expectedTolerationTime time.Duration
556
+ wantErr bool
557
+ }{
558
+ {
559
+ name : "placement annotation not exist" ,
560
+ clusterName : "test-cluster" ,
561
+ annotations : map [string ]string {},
562
+ wantErr : true ,
563
+ },
564
+ {
565
+ name : "placement annotation is invalid JSON" ,
566
+ clusterName : "test-cluster" ,
567
+ annotations : map [string ]string {
568
+ "policy.karmada.io/applied-placement" : "invalid-json" ,
569
+ },
570
+ wantErr : true ,
571
+ },
572
+ {
573
+ name : "placement is nil" ,
574
+ clusterName : "test-cluster" ,
575
+ annotations : map [string ]string {
576
+ "policy.karmada.io/applied-placement" : "" ,
577
+ },
578
+ wantErr : true ,
579
+ },
580
+ {
581
+ name : "cluster not found" ,
582
+ clusterName : "non-existent-cluster" ,
583
+ annotations : map [string ]string {
584
+ "policy.karmada.io/applied-placement" : `{"clusterAffinity":{"clusterNames":["test-cluster"]}}` ,
585
+ },
586
+ expectedNeedEviction : false ,
587
+ expectedTolerationTime : - 1 ,
588
+ wantErr : false ,
589
+ },
590
+ {
591
+ name : "no execute taint eviction disabled" ,
592
+ clusterName : "test-cluster" ,
593
+ annotations : map [string ]string {
594
+ "policy.karmada.io/applied-placement" : `{"clusterAffinity":{"clusterNames":["test-cluster"]}}` ,
595
+ },
596
+ cluster : & clusterv1alpha1.Cluster {
597
+ ObjectMeta : metav1.ObjectMeta {
598
+ Name : "test-cluster" ,
599
+ },
600
+ Spec : clusterv1alpha1.ClusterSpec {
601
+ Taints : []corev1.Taint {
602
+ {
603
+ Key : "test-key" ,
604
+ Effect : corev1 .TaintEffectNoExecute ,
605
+ },
606
+ },
607
+ },
608
+ },
609
+ enableNoExecuteTaintEviction : false ,
610
+ expectedNeedEviction : false ,
611
+ expectedTolerationTime : - 1 ,
612
+ wantErr : false ,
613
+ },
614
+ {
615
+ name : "cluster has no NoExecute taints" ,
616
+ clusterName : "test-cluster" ,
617
+ annotations : map [string ]string {
618
+ "policy.karmada.io/applied-placement" : `{"clusterAffinity":{"clusterNames":["test-cluster"]}}` ,
619
+ },
620
+ cluster : & clusterv1alpha1.Cluster {
621
+ ObjectMeta : metav1.ObjectMeta {
622
+ Name : "test-cluster" ,
623
+ },
624
+ Spec : clusterv1alpha1.ClusterSpec {
625
+ Taints : []corev1.Taint {
626
+ {
627
+ Key : "test-key" ,
628
+ Effect : corev1 .TaintEffectNoSchedule ,
629
+ },
630
+ },
631
+ },
632
+ },
633
+ enableNoExecuteTaintEviction : true ,
634
+ expectedNeedEviction : false ,
635
+ expectedTolerationTime : - 1 ,
636
+ wantErr : false ,
637
+ },
638
+ {
639
+ name : "taint not tolerated - immediate eviction" ,
640
+ clusterName : "test-cluster" ,
641
+ annotations : map [string ]string {
642
+ "policy.karmada.io/applied-placement" : `{"clusterAffinity":{"clusterNames":["test-cluster"]},"clusterTolerations":[]}` ,
643
+ },
644
+ cluster : & clusterv1alpha1.Cluster {
645
+ ObjectMeta : metav1.ObjectMeta {
646
+ Name : "test-cluster" ,
647
+ },
648
+ Spec : clusterv1alpha1.ClusterSpec {
649
+ Taints : []corev1.Taint {
650
+ {
651
+ Key : "test-key" ,
652
+ Effect : corev1 .TaintEffectNoExecute ,
653
+ TimeAdded : & oneSecondAgo ,
654
+ },
655
+ },
656
+ },
657
+ },
658
+ enableNoExecuteTaintEviction : true ,
659
+ expectedNeedEviction : true ,
660
+ expectedTolerationTime : 0 ,
661
+ wantErr : false ,
662
+ },
663
+ {
664
+ name : "taint tolerated with zero toleration seconds - immediate eviction" ,
665
+ clusterName : "test-cluster" ,
666
+ annotations : map [string ]string {
667
+ "policy.karmada.io/applied-placement" : `{"clusterAffinity":{"clusterNames":["test-cluster"]},"clusterTolerations":[{"key":"test-key","operator":"Exists","effect":"NoExecute","tolerationSeconds":0}]}` ,
668
+ },
669
+ cluster : & clusterv1alpha1.Cluster {
670
+ ObjectMeta : metav1.ObjectMeta {
671
+ Name : "test-cluster" ,
672
+ },
673
+ Spec : clusterv1alpha1.ClusterSpec {
674
+ Taints : []corev1.Taint {
675
+ {
676
+ Key : "test-key" ,
677
+ Effect : corev1 .TaintEffectNoExecute ,
678
+ TimeAdded : & oneSecondAgo ,
679
+ },
680
+ },
681
+ },
682
+ },
683
+ enableNoExecuteTaintEviction : true ,
684
+ expectedNeedEviction : true ,
685
+ expectedTolerationTime : 0 ,
686
+ wantErr : false ,
687
+ },
688
+ {
689
+ name : "taint tolerated with positive toleration seconds - wait for toleration time" ,
690
+ clusterName : "test-cluster" ,
691
+ annotations : map [string ]string {
692
+ "policy.karmada.io/applied-placement" : `{"clusterAffinity":{"clusterNames":["test-cluster"]},"clusterTolerations":[{"key":"test-key","operator":"Exists","effect":"NoExecute","tolerationSeconds":60}]}` ,
693
+ },
694
+ cluster : & clusterv1alpha1.Cluster {
695
+ ObjectMeta : metav1.ObjectMeta {
696
+ Name : "test-cluster" ,
697
+ },
698
+ Spec : clusterv1alpha1.ClusterSpec {
699
+ Taints : []corev1.Taint {
700
+ {
701
+ Key : "test-key" ,
702
+ Effect : corev1 .TaintEffectNoExecute ,
703
+ TimeAdded : & oneSecondAgo ,
704
+ },
705
+ },
706
+ },
707
+ },
708
+ enableNoExecuteTaintEviction : true ,
709
+ expectedNeedEviction : false ,
710
+ expectedTolerationTime : 59 * time .Second ,
711
+ wantErr : false ,
712
+ },
713
+ {
714
+ name : "taint tolerated forever - no eviction" ,
715
+ clusterName : "test-cluster" ,
716
+ annotations : map [string ]string {
717
+ "policy.karmada.io/applied-placement" : `{"clusterAffinity":{"clusterNames":["test-cluster"]},"clusterTolerations":[{"key":"test-key","operator":"Exists","effect":"NoExecute"}]}` ,
718
+ },
719
+ cluster : & clusterv1alpha1.Cluster {
720
+ ObjectMeta : metav1.ObjectMeta {
721
+ Name : "test-cluster" ,
722
+ },
723
+ Spec : clusterv1alpha1.ClusterSpec {
724
+ Taints : []corev1.Taint {
725
+ {
726
+ Key : "test-key" ,
727
+ Effect : corev1 .TaintEffectNoExecute ,
728
+ TimeAdded : & oneSecondAgo ,
729
+ },
730
+ },
731
+ },
732
+ },
733
+ enableNoExecuteTaintEviction : true ,
734
+ expectedNeedEviction : false ,
735
+ expectedTolerationTime : - 1 ,
736
+ wantErr : false ,
737
+ },
738
+ {
739
+ name : "multiple taints with mixed tolerations" ,
740
+ clusterName : "test-cluster" ,
741
+ annotations : map [string ]string {
742
+ "policy.karmada.io/applied-placement" : `{"clusterAffinity":{"clusterNames":["test-cluster"]},"clusterTolerations":[{"key":"tolerated-key","operator":"Exists","effect":"NoExecute","tolerationSeconds":30}]}` ,
743
+ },
744
+ cluster : & clusterv1alpha1.Cluster {
745
+ ObjectMeta : metav1.ObjectMeta {
746
+ Name : "test-cluster" ,
747
+ },
748
+ Spec : clusterv1alpha1.ClusterSpec {
749
+ Taints : []corev1.Taint {
750
+ {
751
+ Key : "tolerated-key" ,
752
+ Effect : corev1 .TaintEffectNoExecute ,
753
+ TimeAdded : & oneSecondLater ,
754
+ },
755
+ {
756
+ Key : "not-tolerated-key" ,
757
+ Effect : corev1 .TaintEffectNoExecute ,
758
+ TimeAdded : & oneSecondAgo ,
759
+ },
760
+ },
761
+ },
762
+ },
763
+ enableNoExecuteTaintEviction : true ,
764
+ expectedNeedEviction : true ,
765
+ expectedTolerationTime : 0 ,
766
+ wantErr : false ,
767
+ },
768
+ {
769
+ name : "toleration time expired - immediate eviction" ,
770
+ clusterName : "test-cluster" ,
771
+ annotations : map [string ]string {
772
+ "policy.karmada.io/applied-placement" : `{"clusterAffinity":{"clusterNames":["test-cluster"]},"clusterTolerations":[{"key":"test-key","operator":"Exists","effect":"NoExecute","tolerationSeconds":1}]}` ,
773
+ },
774
+ cluster : & clusterv1alpha1.Cluster {
775
+ ObjectMeta : metav1.ObjectMeta {
776
+ Name : "test-cluster" ,
777
+ },
778
+ Spec : clusterv1alpha1.ClusterSpec {
779
+ Taints : []corev1.Taint {
780
+ {
781
+ Key : "test-key" ,
782
+ Effect : corev1 .TaintEffectNoExecute ,
783
+ TimeAdded : & metav1.Time {Time : now .Add (- 2 * time .Second )}, // 2 seconds ago, tolerance is 1 second
784
+ },
785
+ },
786
+ },
787
+ },
788
+ enableNoExecuteTaintEviction : true ,
789
+ expectedNeedEviction : true ,
790
+ expectedTolerationTime : 0 ,
791
+ wantErr : false ,
792
+ },
793
+ }
794
+
795
+ for _ , tt := range tests {
796
+ t .Run (tt .name , func (t * testing.T ) {
797
+ tc := newNoExecuteTaintManager ()
798
+ tc .EnableNoExecuteTaintEviction = tt .enableNoExecuteTaintEviction
799
+
800
+ // Create cluster if provided
801
+ if tt .cluster != nil {
802
+ if err := tc .Client .Create (context .Background (), tt .cluster ); err != nil {
803
+ t .Fatalf ("failed to create cluster: %v" , err )
804
+ }
805
+ }
806
+
807
+ needEviction , tolerationTime , err := tc .needEviction (tt .clusterName , tt .annotations )
808
+
809
+ // Check error expectation
810
+ if (err != nil ) != tt .wantErr {
811
+ t .Errorf ("needEviction() error = %v, wantErr %v" , err , tt .wantErr )
812
+ return
813
+ }
814
+
815
+ // If we expect an error, don't check other results
816
+ if tt .wantErr {
817
+ return
818
+ }
819
+
820
+ // Check needEviction result
821
+ if needEviction != tt .expectedNeedEviction {
822
+ t .Errorf ("needEviction() needEviction = %v, want %v" , needEviction , tt .expectedNeedEviction )
823
+ }
824
+
825
+ // Check tolerationTime result with tolerance for time-based tests
826
+ if tt .expectedTolerationTime >= 0 && tolerationTime >= 0 {
827
+ // For positive time values, allow 1 second tolerance
828
+ tolerance := 1 * time .Second
829
+ if tolerationTime < tt .expectedTolerationTime - tolerance || tolerationTime > tt .expectedTolerationTime + tolerance {
830
+ t .Errorf ("needEviction() tolerationTime = %v, want %v (±%v)" , tolerationTime , tt .expectedTolerationTime , tolerance )
831
+ }
832
+ } else {
833
+ // For negative values or zero, check exact match
834
+ if tolerationTime != tt .expectedTolerationTime {
835
+ t .Errorf ("needEviction() tolerationTime = %v, want %v" , tolerationTime , tt .expectedTolerationTime )
836
+ }
837
+ }
838
+ })
839
+ }
840
+ }
0 commit comments