@@ -18,9 +18,11 @@ package sync
1818
1919import (
2020 "context"
21+ "fmt"
2122 "reflect"
2223 "sort"
2324 "testing"
25+ "time"
2426
2527 appspub "github.com/openkruise/kruise/apis/apps/pub"
2628 appsv1alpha1 "github.com/openkruise/kruise/apis/apps/v1alpha1"
@@ -32,12 +34,29 @@ import (
3234 v1 "k8s.io/api/core/v1"
3335 "k8s.io/apimachinery/pkg/api/resource"
3436 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
37+ "k8s.io/apimachinery/pkg/runtime"
38+ "k8s.io/apimachinery/pkg/util/intstr"
39+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
3540 "k8s.io/apimachinery/pkg/util/sets"
41+ "k8s.io/client-go/kubernetes/scheme"
3642 "k8s.io/client-go/tools/record"
43+ corev1 "k8s.io/kubernetes/pkg/apis/core/v1"
44+ kubecontroller "k8s.io/kubernetes/pkg/controller"
45+ utilpointer "k8s.io/utils/pointer"
3746 "sigs.k8s.io/controller-runtime/pkg/client"
3847 "sigs.k8s.io/controller-runtime/pkg/client/fake"
3948)
4049
50+ var (
51+ kscheme * runtime.Scheme
52+ )
53+
54+ func init () {
55+ kscheme = runtime .NewScheme ()
56+ utilruntime .Must (appsv1alpha1 .AddToScheme (scheme .Scheme ))
57+ utilruntime .Must (corev1 .AddToScheme (kscheme ))
58+ }
59+
4160func newFakeControl () * realControl {
4261 return & realControl {
4362 Client : fake .NewClientBuilder ().Build (),
@@ -527,3 +546,119 @@ func TestGetOrGenAvailableIDs(t *testing.T) {
527546 t .Fatalf ("expected got random id, but actually %v" , id )
528547 }
529548}
549+
550+ func TestScale (t * testing.T ) {
551+ cases := []struct {
552+ name string
553+ getCloneSets func () [2 ]* appsv1alpha1.CloneSet
554+ getRevisions func () [2 ]string
555+ getPods func () []* v1.Pod
556+ expectedPodsLen int
557+ expectedModified bool
558+ }{
559+ {
560+ name : "cloneSet(replicas=3,maxUnavailable=20%,partition=nil,maxSurge=nil,minReadySeconds=9999), pods=5, and scale replicas 5 -> 3" ,
561+ getCloneSets : func () [2 ]* appsv1alpha1.CloneSet {
562+ obj := & appsv1alpha1.CloneSet {
563+ ObjectMeta : metav1.ObjectMeta {
564+ Name : "sample" ,
565+ },
566+ Spec : appsv1alpha1.CloneSetSpec {
567+ Replicas : utilpointer .Int32 (3 ),
568+ MinReadySeconds : 9999 ,
569+ UpdateStrategy : appsv1alpha1.CloneSetUpdateStrategy {
570+ MaxUnavailable : & intstr.IntOrString {
571+ Type : intstr .String ,
572+ StrVal : "20%" ,
573+ },
574+ },
575+ },
576+ }
577+ return [2 ]* appsv1alpha1.CloneSet {obj .DeepCopy (), obj .DeepCopy ()}
578+ },
579+ getRevisions : func () [2 ]string {
580+ return [2 ]string {"sample-b976d4544" , "sample-b976d4544" }
581+ },
582+ getPods : func () []* v1.Pod {
583+ t := time .Now ().Add (- time .Second * 10 )
584+ obj := & v1.Pod {
585+ ObjectMeta : metav1.ObjectMeta {
586+ Name : "sample" ,
587+ Labels : map [string ]string {
588+ apps .ControllerRevisionHashLabelKey : "sample-b976d4544" ,
589+ },
590+ },
591+ Spec : v1.PodSpec {
592+ Containers : []v1.Container {
593+ {
594+ Name : "main" ,
595+ Image : "sample:v1" ,
596+ },
597+ },
598+ },
599+ Status : v1.PodStatus {
600+ Phase : v1 .PodRunning ,
601+ Conditions : []v1.PodCondition {
602+ {
603+ Type : v1 .PodReady ,
604+ Status : v1 .ConditionTrue ,
605+ LastTransitionTime : metav1.Time {Time : t },
606+ },
607+ },
608+ },
609+ }
610+ return generatePods (obj , 5 )
611+ },
612+ expectedPodsLen : 3 ,
613+ expectedModified : true ,
614+ },
615+ }
616+
617+ for _ , cs := range cases {
618+ t .Run (cs .name , func (t * testing.T ) {
619+ fClient := fake .NewClientBuilder ().WithScheme (kscheme ).Build ()
620+ pods := cs .getPods ()
621+ for _ , pod := range pods {
622+ err := fClient .Create (context .TODO (), pod )
623+ if err != nil {
624+ t .Fatalf (err .Error ())
625+ }
626+ }
627+ rControl := & realControl {
628+ Client : fClient ,
629+ recorder : record .NewFakeRecorder (10 ),
630+ }
631+ modified , err := rControl .Scale (cs .getCloneSets ()[0 ], cs .getCloneSets ()[1 ], cs .getRevisions ()[0 ], cs .getRevisions ()[1 ], pods , nil )
632+ if err != nil {
633+ t .Fatalf (err .Error ())
634+ }
635+ if cs .expectedModified != modified {
636+ t .Fatalf ("expect(%v), but get(%v)" , cs .expectedModified , modified )
637+ }
638+ podList := & v1.PodList {}
639+ err = fClient .List (context .TODO (), podList , & client.ListOptions {})
640+ if err != nil {
641+ t .Fatalf (err .Error ())
642+ }
643+ actives := 0
644+ for _ , pod := range podList .Items {
645+ if kubecontroller .IsPodActive (& pod ) {
646+ actives ++
647+ }
648+ }
649+ if actives != cs .expectedPodsLen {
650+ t .Fatalf ("expect(%v), but get(%v)" , cs .expectedPodsLen , actives )
651+ }
652+ })
653+ }
654+ }
655+
656+ func generatePods (base * v1.Pod , replicas int ) []* v1.Pod {
657+ objs := make ([]* v1.Pod , 0 , replicas )
658+ for i := 0 ; i < replicas ; i ++ {
659+ obj := base .DeepCopy ()
660+ obj .Name = fmt .Sprintf ("%s-%d" , base .Name , i )
661+ objs = append (objs , obj )
662+ }
663+ return objs
664+ }
0 commit comments