1
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