...

Source file src/k8s.io/kubernetes/pkg/apis/autoscaling/v2/defaults_test.go

Documentation: k8s.io/kubernetes/pkg/apis/autoscaling/v2

     1  /*
     2  Copyright 2021 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 v2_test
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	"k8s.io/apimachinery/pkg/runtime"
    24  	"k8s.io/kubernetes/pkg/api/legacyscheme"
    25  
    26  	"github.com/google/go-cmp/cmp"
    27  	"github.com/stretchr/testify/assert"
    28  	autoscalingv2 "k8s.io/api/autoscaling/v2"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/kubernetes/pkg/apis/autoscaling"
    31  	_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
    32  	. "k8s.io/kubernetes/pkg/apis/autoscaling/v2"
    33  	_ "k8s.io/kubernetes/pkg/apis/core/install"
    34  	utilpointer "k8s.io/utils/pointer"
    35  )
    36  
    37  func TestGenerateScaleDownRules(t *testing.T) {
    38  	type TestCase struct {
    39  		rateDownPods                 int32
    40  		rateDownPodsPeriodSeconds    int32
    41  		rateDownPercent              int32
    42  		rateDownPercentPeriodSeconds int32
    43  		stabilizationSeconds         *int32
    44  		selectPolicy                 *autoscalingv2.ScalingPolicySelect
    45  
    46  		expectedPolicies      []autoscalingv2.HPAScalingPolicy
    47  		expectedStabilization *int32
    48  		expectedSelectPolicy  string
    49  		annotation            string
    50  	}
    51  	maxPolicy := autoscalingv2.MaxChangePolicySelect
    52  	minPolicy := autoscalingv2.MinChangePolicySelect
    53  	tests := []TestCase{
    54  		{
    55  			annotation: "Default values",
    56  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
    57  				{Type: autoscalingv2.PercentScalingPolicy, Value: 100, PeriodSeconds: 15},
    58  			},
    59  			expectedStabilization: nil,
    60  			expectedSelectPolicy:  string(autoscalingv2.MaxChangePolicySelect),
    61  		},
    62  		{
    63  			annotation:                   "All parameters are specified",
    64  			rateDownPods:                 1,
    65  			rateDownPodsPeriodSeconds:    2,
    66  			rateDownPercent:              3,
    67  			rateDownPercentPeriodSeconds: 4,
    68  			stabilizationSeconds:         utilpointer.Int32(25),
    69  			selectPolicy:                 &maxPolicy,
    70  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
    71  				{Type: autoscalingv2.PodsScalingPolicy, Value: 1, PeriodSeconds: 2},
    72  				{Type: autoscalingv2.PercentScalingPolicy, Value: 3, PeriodSeconds: 4},
    73  			},
    74  			expectedStabilization: utilpointer.Int32(25),
    75  			expectedSelectPolicy:  string(autoscalingv2.MaxChangePolicySelect),
    76  		},
    77  		{
    78  			annotation:                   "Percent policy is specified",
    79  			rateDownPercent:              1,
    80  			rateDownPercentPeriodSeconds: 2,
    81  			selectPolicy:                 &minPolicy,
    82  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
    83  				{Type: autoscalingv2.PercentScalingPolicy, Value: 1, PeriodSeconds: 2},
    84  			},
    85  			expectedStabilization: nil,
    86  			expectedSelectPolicy:  string(autoscalingv2.MinChangePolicySelect),
    87  		},
    88  		{
    89  			annotation:                "Pods policy is specified",
    90  			rateDownPods:              3,
    91  			rateDownPodsPeriodSeconds: 4,
    92  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
    93  				{Type: autoscalingv2.PodsScalingPolicy, Value: 3, PeriodSeconds: 4},
    94  			},
    95  			expectedStabilization: nil,
    96  			expectedSelectPolicy:  string(autoscalingv2.MaxChangePolicySelect),
    97  		},
    98  	}
    99  	for _, tc := range tests {
   100  		t.Run(tc.annotation, func(t *testing.T) {
   101  			scaleDownRules := &autoscalingv2.HPAScalingRules{
   102  				StabilizationWindowSeconds: tc.stabilizationSeconds,
   103  				SelectPolicy:               tc.selectPolicy,
   104  			}
   105  			if tc.rateDownPods != 0 || tc.rateDownPodsPeriodSeconds != 0 {
   106  				scaleDownRules.Policies = append(scaleDownRules.Policies, autoscalingv2.HPAScalingPolicy{
   107  					Type: autoscalingv2.PodsScalingPolicy, Value: tc.rateDownPods, PeriodSeconds: tc.rateDownPodsPeriodSeconds,
   108  				})
   109  			}
   110  			if tc.rateDownPercent != 0 || tc.rateDownPercentPeriodSeconds != 0 {
   111  				scaleDownRules.Policies = append(scaleDownRules.Policies, autoscalingv2.HPAScalingPolicy{
   112  					Type: autoscalingv2.PercentScalingPolicy, Value: tc.rateDownPercent, PeriodSeconds: tc.rateDownPercentPeriodSeconds,
   113  				})
   114  			}
   115  			down := GenerateHPAScaleDownRules(scaleDownRules)
   116  			assert.EqualValues(t, tc.expectedPolicies, down.Policies)
   117  			if tc.expectedStabilization != nil {
   118  				assert.Equal(t, *tc.expectedStabilization, *down.StabilizationWindowSeconds)
   119  			} else {
   120  				assert.Equal(t, tc.expectedStabilization, down.StabilizationWindowSeconds)
   121  			}
   122  			assert.Equal(t, autoscalingv2.ScalingPolicySelect(tc.expectedSelectPolicy), *down.SelectPolicy)
   123  		})
   124  	}
   125  }
   126  
   127  func TestGenerateScaleUpRules(t *testing.T) {
   128  	type TestCase struct {
   129  		rateUpPods                 int32
   130  		rateUpPodsPeriodSeconds    int32
   131  		rateUpPercent              int32
   132  		rateUpPercentPeriodSeconds int32
   133  		stabilizationSeconds       *int32
   134  		selectPolicy               *autoscalingv2.ScalingPolicySelect
   135  
   136  		expectedPolicies      []autoscalingv2.HPAScalingPolicy
   137  		expectedStabilization *int32
   138  		expectedSelectPolicy  string
   139  		annotation            string
   140  	}
   141  	maxPolicy := autoscalingv2.MaxChangePolicySelect
   142  	minPolicy := autoscalingv2.MinChangePolicySelect
   143  	tests := []TestCase{
   144  		{
   145  			annotation: "Default values",
   146  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
   147  				{Type: autoscalingv2.PodsScalingPolicy, Value: 4, PeriodSeconds: 15},
   148  				{Type: autoscalingv2.PercentScalingPolicy, Value: 100, PeriodSeconds: 15},
   149  			},
   150  			expectedStabilization: utilpointer.Int32(0),
   151  			expectedSelectPolicy:  string(autoscalingv2.MaxChangePolicySelect),
   152  		},
   153  		{
   154  			annotation:                 "All parameters are specified",
   155  			rateUpPods:                 1,
   156  			rateUpPodsPeriodSeconds:    2,
   157  			rateUpPercent:              3,
   158  			rateUpPercentPeriodSeconds: 4,
   159  			stabilizationSeconds:       utilpointer.Int32(25),
   160  			selectPolicy:               &maxPolicy,
   161  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
   162  				{Type: autoscalingv2.PodsScalingPolicy, Value: 1, PeriodSeconds: 2},
   163  				{Type: autoscalingv2.PercentScalingPolicy, Value: 3, PeriodSeconds: 4},
   164  			},
   165  			expectedStabilization: utilpointer.Int32(25),
   166  			expectedSelectPolicy:  string(autoscalingv2.MaxChangePolicySelect),
   167  		},
   168  		{
   169  			annotation:              "Pod policy is specified",
   170  			rateUpPods:              1,
   171  			rateUpPodsPeriodSeconds: 2,
   172  			selectPolicy:            &minPolicy,
   173  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
   174  				{Type: autoscalingv2.PodsScalingPolicy, Value: 1, PeriodSeconds: 2},
   175  			},
   176  			expectedStabilization: utilpointer.Int32(0),
   177  			expectedSelectPolicy:  string(autoscalingv2.MinChangePolicySelect),
   178  		},
   179  		{
   180  			annotation:                 "Percent policy is specified",
   181  			rateUpPercent:              7,
   182  			rateUpPercentPeriodSeconds: 10,
   183  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
   184  				{Type: autoscalingv2.PercentScalingPolicy, Value: 7, PeriodSeconds: 10},
   185  			},
   186  			expectedStabilization: utilpointer.Int32(0),
   187  			expectedSelectPolicy:  string(autoscalingv2.MaxChangePolicySelect),
   188  		},
   189  		{
   190  			annotation:              "Pod policy and stabilization window are specified",
   191  			rateUpPodsPeriodSeconds: 2,
   192  			stabilizationSeconds:    utilpointer.Int32(25),
   193  			rateUpPods:              4,
   194  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
   195  				{Type: autoscalingv2.PodsScalingPolicy, Value: 4, PeriodSeconds: 2},
   196  			},
   197  			expectedStabilization: utilpointer.Int32(25),
   198  			expectedSelectPolicy:  string(autoscalingv2.MaxChangePolicySelect),
   199  		},
   200  		{
   201  			annotation:                 "Percent policy and stabilization window are specified",
   202  			rateUpPercent:              7,
   203  			rateUpPercentPeriodSeconds: 60,
   204  			stabilizationSeconds:       utilpointer.Int32(25),
   205  			expectedPolicies: []autoscalingv2.HPAScalingPolicy{
   206  				{Type: autoscalingv2.PercentScalingPolicy, Value: 7, PeriodSeconds: 60},
   207  			},
   208  			expectedStabilization: utilpointer.Int32(25),
   209  			expectedSelectPolicy:  string(autoscalingv2.MaxChangePolicySelect),
   210  		},
   211  	}
   212  	for _, tc := range tests {
   213  		t.Run(tc.annotation, func(t *testing.T) {
   214  			scaleUpRules := &autoscalingv2.HPAScalingRules{
   215  				StabilizationWindowSeconds: tc.stabilizationSeconds,
   216  				SelectPolicy:               tc.selectPolicy,
   217  			}
   218  			if tc.rateUpPods != 0 || tc.rateUpPodsPeriodSeconds != 0 {
   219  				scaleUpRules.Policies = append(scaleUpRules.Policies, autoscalingv2.HPAScalingPolicy{
   220  					Type: autoscalingv2.PodsScalingPolicy, Value: tc.rateUpPods, PeriodSeconds: tc.rateUpPodsPeriodSeconds,
   221  				})
   222  			}
   223  			if tc.rateUpPercent != 0 || tc.rateUpPercentPeriodSeconds != 0 {
   224  				scaleUpRules.Policies = append(scaleUpRules.Policies, autoscalingv2.HPAScalingPolicy{
   225  					Type: autoscalingv2.PercentScalingPolicy, Value: tc.rateUpPercent, PeriodSeconds: tc.rateUpPercentPeriodSeconds,
   226  				})
   227  			}
   228  			up := GenerateHPAScaleUpRules(scaleUpRules)
   229  			assert.Equal(t, tc.expectedPolicies, up.Policies)
   230  			if tc.expectedStabilization != nil {
   231  				assert.Equal(t, *tc.expectedStabilization, *up.StabilizationWindowSeconds)
   232  			} else {
   233  				assert.Equal(t, tc.expectedStabilization, up.StabilizationWindowSeconds)
   234  			}
   235  
   236  			assert.Equal(t, autoscalingv2.ScalingPolicySelect(tc.expectedSelectPolicy), *up.SelectPolicy)
   237  		})
   238  	}
   239  }
   240  
   241  func TestHorizontalPodAutoscalerAnnotations(t *testing.T) {
   242  	tests := []struct {
   243  		hpa  autoscalingv2.HorizontalPodAutoscaler
   244  		test string
   245  	}{
   246  		{
   247  			hpa: autoscalingv2.HorizontalPodAutoscaler{
   248  				ObjectMeta: metav1.ObjectMeta{
   249  					Annotations: map[string]string{
   250  						autoscaling.HorizontalPodAutoscalerConditionsAnnotation: "",
   251  						autoscaling.MetricSpecsAnnotation:                       "",
   252  						autoscaling.BehaviorSpecsAnnotation:                     "",
   253  						autoscaling.MetricStatusesAnnotation:                    "",
   254  					},
   255  				},
   256  			},
   257  			test: "test empty value for Annotations",
   258  		},
   259  		{
   260  			hpa: autoscalingv2.HorizontalPodAutoscaler{
   261  				ObjectMeta: metav1.ObjectMeta{
   262  					Annotations: map[string]string{
   263  						autoscaling.HorizontalPodAutoscalerConditionsAnnotation: "abc",
   264  						autoscaling.MetricSpecsAnnotation:                       "abc",
   265  						autoscaling.BehaviorSpecsAnnotation:                     "abc",
   266  						autoscaling.MetricStatusesAnnotation:                    "abc",
   267  					},
   268  				},
   269  			},
   270  			test: "test random value for Annotations",
   271  		},
   272  		{
   273  			hpa: autoscalingv2.HorizontalPodAutoscaler{
   274  				ObjectMeta: metav1.ObjectMeta{
   275  					Annotations: map[string]string{
   276  						autoscaling.HorizontalPodAutoscalerConditionsAnnotation: "[]",
   277  						autoscaling.MetricSpecsAnnotation:                       "[]",
   278  						autoscaling.BehaviorSpecsAnnotation:                     "[]",
   279  						autoscaling.MetricStatusesAnnotation:                    "[]",
   280  					},
   281  				},
   282  			},
   283  			test: "test empty array value for Annotations",
   284  		},
   285  	}
   286  
   287  	for _, test := range tests {
   288  		hpa := &test.hpa
   289  		hpaBeforeMuatate := *hpa.DeepCopy()
   290  		obj := roundTrip(t, runtime.Object(hpa))
   291  		final_obj, ok := obj.(*autoscalingv2.HorizontalPodAutoscaler)
   292  		if !ok {
   293  			t.Fatalf("unexpected object: %v", obj)
   294  		}
   295  		if !reflect.DeepEqual(*hpa, hpaBeforeMuatate) {
   296  			t.Errorf("diff: %v", cmp.Diff(*hpa, hpaBeforeMuatate))
   297  			t.Errorf("expected: %#v\n actual:   %#v", *hpa, hpaBeforeMuatate)
   298  		}
   299  
   300  		if len(final_obj.ObjectMeta.Annotations) != 0 {
   301  			t.Fatalf("unexpected annotations: %v", final_obj.ObjectMeta.Annotations)
   302  		}
   303  	}
   304  }
   305  
   306  func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
   307  	data, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(SchemeGroupVersion), obj)
   308  	if err != nil {
   309  		t.Errorf("%v\n %#v", err, obj)
   310  		return nil
   311  	}
   312  	obj2, err := runtime.Decode(legacyscheme.Codecs.UniversalDecoder(), data)
   313  	if err != nil {
   314  		t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
   315  		return nil
   316  	}
   317  	obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
   318  	err = legacyscheme.Scheme.Convert(obj2, obj3, nil)
   319  	if err != nil {
   320  		t.Errorf("%v\nSource: %#v", err, obj2)
   321  		return nil
   322  	}
   323  	return obj3
   324  }
   325  

View as plain text