k8s.io/kubernetes@v1.29.3/pkg/apis/autoscaling/v2/defaults_test.go (about) 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 }