1
16
17 package v1beta2_test
18
19 import (
20 "reflect"
21 "testing"
22
23 appsv1beta2 "k8s.io/api/apps/v1beta2"
24 v1 "k8s.io/api/core/v1"
25 apiequality "k8s.io/apimachinery/pkg/api/equality"
26 "k8s.io/apimachinery/pkg/api/resource"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/util/intstr"
30 utilfeature "k8s.io/apiserver/pkg/util/feature"
31 featuregatetesting "k8s.io/component-base/featuregate/testing"
32 "k8s.io/kubernetes/pkg/api/legacyscheme"
33 _ "k8s.io/kubernetes/pkg/apis/apps/install"
34 . "k8s.io/kubernetes/pkg/apis/apps/v1beta2"
35 _ "k8s.io/kubernetes/pkg/apis/core/install"
36 "k8s.io/kubernetes/pkg/features"
37 "k8s.io/utils/ptr"
38 )
39
40 func TestSetDefaultDaemonSetSpec(t *testing.T) {
41 defaultLabels := map[string]string{"foo": "bar"}
42 maxUnavailable := intstr.FromInt32(1)
43 maxSurge := intstr.FromInt32(0)
44 period := int64(v1.DefaultTerminationGracePeriodSeconds)
45 defaultTemplate := v1.PodTemplateSpec{
46 Spec: v1.PodSpec{
47 DNSPolicy: v1.DNSClusterFirst,
48 RestartPolicy: v1.RestartPolicyAlways,
49 SecurityContext: &v1.PodSecurityContext{},
50 TerminationGracePeriodSeconds: &period,
51 SchedulerName: v1.DefaultSchedulerName,
52 },
53 ObjectMeta: metav1.ObjectMeta{
54 Labels: defaultLabels,
55 },
56 }
57 templateNoLabel := v1.PodTemplateSpec{
58 Spec: v1.PodSpec{
59 DNSPolicy: v1.DNSClusterFirst,
60 RestartPolicy: v1.RestartPolicyAlways,
61 SecurityContext: &v1.PodSecurityContext{},
62 TerminationGracePeriodSeconds: &period,
63 SchedulerName: v1.DefaultSchedulerName,
64 },
65 }
66 tests := []struct {
67 original *appsv1beta2.DaemonSet
68 expected *appsv1beta2.DaemonSet
69 }{
70 {
71 original: &appsv1beta2.DaemonSet{
72 Spec: appsv1beta2.DaemonSetSpec{
73 Template: defaultTemplate,
74 },
75 },
76 expected: &appsv1beta2.DaemonSet{
77 ObjectMeta: metav1.ObjectMeta{
78 Labels: defaultLabels,
79 },
80 Spec: appsv1beta2.DaemonSetSpec{
81 Template: defaultTemplate,
82 UpdateStrategy: appsv1beta2.DaemonSetUpdateStrategy{
83 Type: appsv1beta2.RollingUpdateDaemonSetStrategyType,
84 RollingUpdate: &appsv1beta2.RollingUpdateDaemonSet{
85 MaxUnavailable: &maxUnavailable,
86 MaxSurge: &maxSurge,
87 },
88 },
89 RevisionHistoryLimit: ptr.To[int32](10),
90 },
91 },
92 },
93 {
94 original: &appsv1beta2.DaemonSet{
95 ObjectMeta: metav1.ObjectMeta{
96 Labels: map[string]string{
97 "bar": "foo",
98 },
99 },
100 Spec: appsv1beta2.DaemonSetSpec{
101 Template: defaultTemplate,
102 RevisionHistoryLimit: ptr.To[int32](1),
103 },
104 },
105 expected: &appsv1beta2.DaemonSet{
106 ObjectMeta: metav1.ObjectMeta{
107 Labels: map[string]string{
108 "bar": "foo",
109 },
110 },
111 Spec: appsv1beta2.DaemonSetSpec{
112 Template: defaultTemplate,
113 UpdateStrategy: appsv1beta2.DaemonSetUpdateStrategy{
114 Type: appsv1beta2.RollingUpdateDaemonSetStrategyType,
115 RollingUpdate: &appsv1beta2.RollingUpdateDaemonSet{
116 MaxUnavailable: &maxUnavailable,
117 MaxSurge: &maxSurge,
118 },
119 },
120 RevisionHistoryLimit: ptr.To[int32](1),
121 },
122 },
123 },
124 {
125 original: &appsv1beta2.DaemonSet{
126 Spec: appsv1beta2.DaemonSetSpec{
127 Template: templateNoLabel,
128 UpdateStrategy: appsv1beta2.DaemonSetUpdateStrategy{
129 Type: appsv1beta2.OnDeleteDaemonSetStrategyType,
130 },
131 },
132 },
133 expected: &appsv1beta2.DaemonSet{
134 Spec: appsv1beta2.DaemonSetSpec{
135 Template: templateNoLabel,
136 UpdateStrategy: appsv1beta2.DaemonSetUpdateStrategy{
137 Type: appsv1beta2.OnDeleteDaemonSetStrategyType,
138 },
139 RevisionHistoryLimit: ptr.To[int32](10),
140 },
141 },
142 },
143 {
144 original: &appsv1beta2.DaemonSet{
145 Spec: appsv1beta2.DaemonSetSpec{},
146 },
147 expected: &appsv1beta2.DaemonSet{
148 Spec: appsv1beta2.DaemonSetSpec{
149 Template: templateNoLabel,
150 UpdateStrategy: appsv1beta2.DaemonSetUpdateStrategy{
151 Type: appsv1beta2.RollingUpdateDaemonSetStrategyType,
152 RollingUpdate: &appsv1beta2.RollingUpdateDaemonSet{
153 MaxUnavailable: &maxUnavailable,
154 MaxSurge: &maxSurge,
155 },
156 },
157 RevisionHistoryLimit: ptr.To[int32](10),
158 },
159 },
160 },
161 }
162
163 for i, test := range tests {
164 original := test.original
165 expected := test.expected
166 obj2 := roundTrip(t, runtime.Object(original))
167 got, ok := obj2.(*appsv1beta2.DaemonSet)
168 if !ok {
169 t.Errorf("(%d) unexpected object: %v", i, got)
170 t.FailNow()
171 }
172 if !apiequality.Semantic.DeepEqual(got.Spec, expected.Spec) {
173 t.Errorf("(%d) got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", i, got.Spec, expected.Spec)
174 }
175 }
176 }
177
178 func TestSetDefaultStatefulSet(t *testing.T) {
179 defaultLabels := map[string]string{"foo": "bar"}
180 var defaultPartition int32 = 0
181 var notTheDefaultPartition int32 = 42
182 var defaultReplicas int32 = 1
183
184 period := int64(v1.DefaultTerminationGracePeriodSeconds)
185 defaultTemplate := v1.PodTemplateSpec{
186 Spec: v1.PodSpec{
187 DNSPolicy: v1.DNSClusterFirst,
188 RestartPolicy: v1.RestartPolicyAlways,
189 SecurityContext: &v1.PodSecurityContext{},
190 TerminationGracePeriodSeconds: &period,
191 SchedulerName: v1.DefaultSchedulerName,
192 },
193 ObjectMeta: metav1.ObjectMeta{
194 Labels: defaultLabels,
195 },
196 }
197
198 tests := []struct {
199 name string
200 original *appsv1beta2.StatefulSet
201 expected *appsv1beta2.StatefulSet
202 enableMaxUnavailablePolicy bool
203 enableStatefulSetAutoDelete bool
204 }{
205 {
206 name: "labels and default update strategy",
207 original: &appsv1beta2.StatefulSet{
208 Spec: appsv1beta2.StatefulSetSpec{
209 Template: defaultTemplate,
210 },
211 },
212 expected: &appsv1beta2.StatefulSet{
213 ObjectMeta: metav1.ObjectMeta{
214 Labels: defaultLabels,
215 },
216 Spec: appsv1beta2.StatefulSetSpec{
217 Replicas: &defaultReplicas,
218 MinReadySeconds: int32(0),
219 Template: defaultTemplate,
220 PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
221 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
222 Type: appsv1beta2.RollingUpdateStatefulSetStrategyType,
223 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
224 Partition: &defaultPartition,
225 },
226 },
227 RevisionHistoryLimit: ptr.To[int32](10),
228 },
229 },
230 },
231 {
232 name: "Alternate update strategy",
233 original: &appsv1beta2.StatefulSet{
234 Spec: appsv1beta2.StatefulSetSpec{
235 Template: defaultTemplate,
236 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
237 Type: appsv1beta2.OnDeleteStatefulSetStrategyType,
238 },
239 },
240 },
241 expected: &appsv1beta2.StatefulSet{
242 ObjectMeta: metav1.ObjectMeta{
243 Labels: defaultLabels,
244 },
245 Spec: appsv1beta2.StatefulSetSpec{
246 Replicas: &defaultReplicas,
247 MinReadySeconds: int32(0),
248 Template: defaultTemplate,
249 PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
250 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
251 Type: appsv1beta2.OnDeleteStatefulSetStrategyType,
252 },
253 RevisionHistoryLimit: ptr.To[int32](10),
254 },
255 },
256 },
257 {
258 name: "Parallel pod management policy.",
259 original: &appsv1beta2.StatefulSet{
260 Spec: appsv1beta2.StatefulSetSpec{
261 Template: defaultTemplate,
262 PodManagementPolicy: appsv1beta2.ParallelPodManagement,
263 },
264 },
265 expected: &appsv1beta2.StatefulSet{
266 ObjectMeta: metav1.ObjectMeta{
267 Labels: defaultLabels,
268 },
269 Spec: appsv1beta2.StatefulSetSpec{
270 Replicas: &defaultReplicas,
271 MinReadySeconds: int32(0),
272 Template: defaultTemplate,
273 PodManagementPolicy: appsv1beta2.ParallelPodManagement,
274 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
275 Type: appsv1beta2.RollingUpdateStatefulSetStrategyType,
276 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
277 Partition: &defaultPartition,
278 },
279 },
280 RevisionHistoryLimit: ptr.To[int32](10),
281 },
282 },
283 },
284 {
285 name: "MaxUnavailable disabled, with maxUnavailable not specified",
286 original: &appsv1beta2.StatefulSet{
287 Spec: appsv1beta2.StatefulSetSpec{
288 Template: defaultTemplate,
289 },
290 },
291 expected: &appsv1beta2.StatefulSet{
292 ObjectMeta: metav1.ObjectMeta{
293 Labels: defaultLabels,
294 },
295 Spec: appsv1beta2.StatefulSetSpec{
296 Replicas: &defaultReplicas,
297 Template: defaultTemplate,
298 PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
299 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
300 Type: appsv1beta2.RollingUpdateStatefulSetStrategyType,
301 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
302 Partition: ptr.To[int32](0),
303 },
304 },
305 RevisionHistoryLimit: ptr.To[int32](10),
306 },
307 },
308 enableMaxUnavailablePolicy: false,
309 },
310 {
311 name: "MaxUnavailable disabled, with default maxUnavailable specified",
312 original: &appsv1beta2.StatefulSet{
313 Spec: appsv1beta2.StatefulSetSpec{
314 Template: defaultTemplate,
315 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
316 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
317 Partition: &defaultPartition,
318 MaxUnavailable: ptr.To(intstr.FromInt32(1)),
319 },
320 },
321 },
322 },
323 expected: &appsv1beta2.StatefulSet{
324 ObjectMeta: metav1.ObjectMeta{
325 Labels: defaultLabels,
326 },
327 Spec: appsv1beta2.StatefulSetSpec{
328 Replicas: &defaultReplicas,
329 Template: defaultTemplate,
330 PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
331 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
332 Type: appsv1beta2.RollingUpdateStatefulSetStrategyType,
333 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
334 Partition: ptr.To[int32](0),
335 MaxUnavailable: ptr.To(intstr.FromInt32(1)),
336 },
337 },
338 RevisionHistoryLimit: ptr.To[int32](10),
339 },
340 },
341 enableMaxUnavailablePolicy: false,
342 },
343 {
344 name: "MaxUnavailable disabled, with non default maxUnavailable specified",
345 original: &appsv1beta2.StatefulSet{
346 Spec: appsv1beta2.StatefulSetSpec{
347 Template: defaultTemplate,
348 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
349 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
350 Partition: ¬TheDefaultPartition,
351 MaxUnavailable: ptr.To(intstr.FromInt32(3)),
352 },
353 },
354 },
355 },
356 expected: &appsv1beta2.StatefulSet{
357 ObjectMeta: metav1.ObjectMeta{
358 Labels: defaultLabels,
359 },
360 Spec: appsv1beta2.StatefulSetSpec{
361 Replicas: &defaultReplicas,
362 Template: defaultTemplate,
363 PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
364 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
365 Type: appsv1beta2.RollingUpdateStatefulSetStrategyType,
366 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
367 Partition: ptr.To[int32](42),
368 MaxUnavailable: ptr.To(intstr.FromInt32(3)),
369 },
370 },
371 RevisionHistoryLimit: ptr.To[int32](10),
372 },
373 },
374 enableMaxUnavailablePolicy: false,
375 },
376 {
377 name: "MaxUnavailable enabled, with no maxUnavailable specified",
378 original: &appsv1beta2.StatefulSet{
379 Spec: appsv1beta2.StatefulSetSpec{
380 Template: defaultTemplate,
381 },
382 },
383 expected: &appsv1beta2.StatefulSet{
384 ObjectMeta: metav1.ObjectMeta{
385 Labels: defaultLabels,
386 },
387 Spec: appsv1beta2.StatefulSetSpec{
388 Replicas: &defaultReplicas,
389 Template: defaultTemplate,
390 PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
391 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
392 Type: appsv1beta2.RollingUpdateStatefulSetStrategyType,
393 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
394 Partition: ptr.To[int32](0),
395 MaxUnavailable: ptr.To(intstr.FromInt32(1)),
396 },
397 },
398 RevisionHistoryLimit: ptr.To[int32](10),
399 },
400 },
401 enableMaxUnavailablePolicy: true,
402 },
403 {
404 name: "MaxUnavailable enabled, with non default maxUnavailable specified",
405 original: &appsv1beta2.StatefulSet{
406 Spec: appsv1beta2.StatefulSetSpec{
407 Template: defaultTemplate,
408 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
409 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
410 Partition: ¬TheDefaultPartition,
411 MaxUnavailable: ptr.To(intstr.FromInt32(3)),
412 },
413 },
414 },
415 },
416 expected: &appsv1beta2.StatefulSet{
417 ObjectMeta: metav1.ObjectMeta{
418 Labels: defaultLabels,
419 },
420 Spec: appsv1beta2.StatefulSetSpec{
421 Replicas: &defaultReplicas,
422 Template: defaultTemplate,
423 PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
424 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
425 Type: appsv1beta2.RollingUpdateStatefulSetStrategyType,
426 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
427 Partition: ptr.To[int32](42),
428 MaxUnavailable: ptr.To(intstr.FromInt32(3)),
429 },
430 },
431 RevisionHistoryLimit: ptr.To[int32](10),
432 },
433 },
434 enableMaxUnavailablePolicy: true,
435 },
436 {
437 name: "StatefulSetAutoDeletePVC enabled",
438 original: &appsv1beta2.StatefulSet{
439 Spec: appsv1beta2.StatefulSetSpec{
440 Template: defaultTemplate,
441 },
442 },
443 expected: &appsv1beta2.StatefulSet{
444 ObjectMeta: metav1.ObjectMeta{
445 Labels: defaultLabels,
446 },
447 Spec: appsv1beta2.StatefulSetSpec{
448 Replicas: &defaultReplicas,
449 Template: defaultTemplate,
450 PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
451 UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
452 Type: appsv1beta2.RollingUpdateStatefulSetStrategyType,
453 RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{
454 Partition: &defaultPartition,
455 },
456 },
457 RevisionHistoryLimit: ptr.To[int32](10),
458 PersistentVolumeClaimRetentionPolicy: &appsv1beta2.StatefulSetPersistentVolumeClaimRetentionPolicy{
459 WhenDeleted: appsv1beta2.RetainPersistentVolumeClaimRetentionPolicyType,
460 WhenScaled: appsv1beta2.RetainPersistentVolumeClaimRetentionPolicyType,
461 },
462 },
463 },
464 enableStatefulSetAutoDelete: true,
465 },
466 }
467
468 for _, test := range tests {
469 test := test
470 t.Run(test.name, func(t *testing.T) {
471 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MaxUnavailableStatefulSet, test.enableMaxUnavailablePolicy)()
472 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StatefulSetAutoDeletePVC, test.enableStatefulSetAutoDelete)()
473 obj2 := roundTrip(t, runtime.Object(test.original))
474 got, ok := obj2.(*appsv1beta2.StatefulSet)
475 if !ok {
476 t.Errorf("unexpected object: %v", got)
477 t.FailNow()
478 }
479 if !apiequality.Semantic.DeepEqual(got.Spec, test.expected.Spec) {
480 t.Errorf("got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", got.Spec, test.expected.Spec)
481 }
482 })
483 }
484 }
485
486 func TestSetDefaultDeployment(t *testing.T) {
487 defaultIntOrString := intstr.FromString("25%")
488 differentIntOrString := intstr.FromInt32(5)
489 period := int64(v1.DefaultTerminationGracePeriodSeconds)
490 defaultTemplate := v1.PodTemplateSpec{
491 Spec: v1.PodSpec{
492 DNSPolicy: v1.DNSClusterFirst,
493 RestartPolicy: v1.RestartPolicyAlways,
494 SecurityContext: &v1.PodSecurityContext{},
495 TerminationGracePeriodSeconds: &period,
496 SchedulerName: v1.DefaultSchedulerName,
497 },
498 }
499 tests := []struct {
500 original *appsv1beta2.Deployment
501 expected *appsv1beta2.Deployment
502 }{
503 {
504 original: &appsv1beta2.Deployment{},
505 expected: &appsv1beta2.Deployment{
506 Spec: appsv1beta2.DeploymentSpec{
507 Replicas: ptr.To[int32](1),
508 Strategy: appsv1beta2.DeploymentStrategy{
509 Type: appsv1beta2.RollingUpdateDeploymentStrategyType,
510 RollingUpdate: &appsv1beta2.RollingUpdateDeployment{
511 MaxSurge: &defaultIntOrString,
512 MaxUnavailable: &defaultIntOrString,
513 },
514 },
515 RevisionHistoryLimit: ptr.To[int32](10),
516 ProgressDeadlineSeconds: ptr.To[int32](600),
517 Template: defaultTemplate,
518 },
519 },
520 },
521 {
522 original: &appsv1beta2.Deployment{
523 Spec: appsv1beta2.DeploymentSpec{
524 Replicas: ptr.To[int32](5),
525 Strategy: appsv1beta2.DeploymentStrategy{
526 RollingUpdate: &appsv1beta2.RollingUpdateDeployment{
527 MaxSurge: &differentIntOrString,
528 },
529 },
530 },
531 },
532 expected: &appsv1beta2.Deployment{
533 Spec: appsv1beta2.DeploymentSpec{
534 Replicas: ptr.To[int32](5),
535 Strategy: appsv1beta2.DeploymentStrategy{
536 Type: appsv1beta2.RollingUpdateDeploymentStrategyType,
537 RollingUpdate: &appsv1beta2.RollingUpdateDeployment{
538 MaxSurge: &differentIntOrString,
539 MaxUnavailable: &defaultIntOrString,
540 },
541 },
542 RevisionHistoryLimit: ptr.To[int32](10),
543 ProgressDeadlineSeconds: ptr.To[int32](600),
544 Template: defaultTemplate,
545 },
546 },
547 },
548 {
549 original: &appsv1beta2.Deployment{
550 Spec: appsv1beta2.DeploymentSpec{
551 Replicas: ptr.To[int32](3),
552 Strategy: appsv1beta2.DeploymentStrategy{
553 Type: appsv1beta2.RollingUpdateDeploymentStrategyType,
554 RollingUpdate: nil,
555 },
556 },
557 },
558 expected: &appsv1beta2.Deployment{
559 Spec: appsv1beta2.DeploymentSpec{
560 Replicas: ptr.To[int32](3),
561 Strategy: appsv1beta2.DeploymentStrategy{
562 Type: appsv1beta2.RollingUpdateDeploymentStrategyType,
563 RollingUpdate: &appsv1beta2.RollingUpdateDeployment{
564 MaxSurge: &defaultIntOrString,
565 MaxUnavailable: &defaultIntOrString,
566 },
567 },
568 RevisionHistoryLimit: ptr.To[int32](10),
569 ProgressDeadlineSeconds: ptr.To[int32](600),
570 Template: defaultTemplate,
571 },
572 },
573 },
574 {
575 original: &appsv1beta2.Deployment{
576 Spec: appsv1beta2.DeploymentSpec{
577 Replicas: ptr.To[int32](5),
578 Strategy: appsv1beta2.DeploymentStrategy{
579 Type: appsv1beta2.RecreateDeploymentStrategyType,
580 },
581 RevisionHistoryLimit: ptr.To[int32](0),
582 },
583 },
584 expected: &appsv1beta2.Deployment{
585 Spec: appsv1beta2.DeploymentSpec{
586 Replicas: ptr.To[int32](5),
587 Strategy: appsv1beta2.DeploymentStrategy{
588 Type: appsv1beta2.RecreateDeploymentStrategyType,
589 },
590 RevisionHistoryLimit: ptr.To[int32](0),
591 ProgressDeadlineSeconds: ptr.To[int32](600),
592 Template: defaultTemplate,
593 },
594 },
595 },
596 {
597 original: &appsv1beta2.Deployment{
598 Spec: appsv1beta2.DeploymentSpec{
599 Replicas: ptr.To[int32](5),
600 Strategy: appsv1beta2.DeploymentStrategy{
601 Type: appsv1beta2.RecreateDeploymentStrategyType,
602 },
603 ProgressDeadlineSeconds: ptr.To[int32](30),
604 RevisionHistoryLimit: ptr.To[int32](2),
605 },
606 },
607 expected: &appsv1beta2.Deployment{
608 Spec: appsv1beta2.DeploymentSpec{
609 Replicas: ptr.To[int32](5),
610 Strategy: appsv1beta2.DeploymentStrategy{
611 Type: appsv1beta2.RecreateDeploymentStrategyType,
612 },
613 ProgressDeadlineSeconds: ptr.To[int32](30),
614 RevisionHistoryLimit: ptr.To[int32](2),
615 Template: defaultTemplate,
616 },
617 },
618 },
619 }
620
621 for _, test := range tests {
622 original := test.original
623 expected := test.expected
624 obj2 := roundTrip(t, runtime.Object(original))
625 got, ok := obj2.(*appsv1beta2.Deployment)
626 if !ok {
627 t.Errorf("unexpected object: %v", got)
628 t.FailNow()
629 }
630 if !apiequality.Semantic.DeepEqual(got.Spec, expected.Spec) {
631 t.Errorf("object mismatch!\nexpected:\n\t%+v\ngot:\n\t%+v", got.Spec, expected.Spec)
632 }
633 }
634 }
635
636 func TestDefaultDeploymentAvailability(t *testing.T) {
637 d := roundTrip(t, runtime.Object(&appsv1beta2.Deployment{})).(*appsv1beta2.Deployment)
638
639 maxUnavailable, err := intstr.GetScaledValueFromIntOrPercent(d.Spec.Strategy.RollingUpdate.MaxUnavailable, int(*(d.Spec.Replicas)), false)
640 if err != nil {
641 t.Fatalf("unexpected error: %v", err)
642 }
643
644 if *(d.Spec.Replicas)-int32(maxUnavailable) <= 0 {
645 t.Fatalf("the default value of maxUnavailable can lead to no active replicas during rolling update")
646 }
647 }
648
649 func TestSetDefaultReplicaSetReplicas(t *testing.T) {
650 tests := []struct {
651 rs appsv1beta2.ReplicaSet
652 expectReplicas int32
653 }{
654 {
655 rs: appsv1beta2.ReplicaSet{
656 Spec: appsv1beta2.ReplicaSetSpec{
657 Template: v1.PodTemplateSpec{
658 ObjectMeta: metav1.ObjectMeta{
659 Labels: map[string]string{
660 "foo": "bar",
661 },
662 },
663 },
664 },
665 },
666 expectReplicas: 1,
667 },
668 {
669 rs: appsv1beta2.ReplicaSet{
670 Spec: appsv1beta2.ReplicaSetSpec{
671 Replicas: ptr.To[int32](0),
672 Template: v1.PodTemplateSpec{
673 ObjectMeta: metav1.ObjectMeta{
674 Labels: map[string]string{
675 "foo": "bar",
676 },
677 },
678 },
679 },
680 },
681 expectReplicas: 0,
682 },
683 {
684 rs: appsv1beta2.ReplicaSet{
685 Spec: appsv1beta2.ReplicaSetSpec{
686 Replicas: ptr.To[int32](3),
687 Template: v1.PodTemplateSpec{
688 ObjectMeta: metav1.ObjectMeta{
689 Labels: map[string]string{
690 "foo": "bar",
691 },
692 },
693 },
694 },
695 },
696 expectReplicas: 3,
697 },
698 }
699
700 for _, test := range tests {
701 rs := &test.rs
702 obj2 := roundTrip(t, runtime.Object(rs))
703 rs2, ok := obj2.(*appsv1beta2.ReplicaSet)
704 if !ok {
705 t.Errorf("unexpected object: %v", rs2)
706 t.FailNow()
707 }
708 if rs2.Spec.Replicas == nil {
709 t.Errorf("unexpected nil Replicas")
710 } else if test.expectReplicas != *rs2.Spec.Replicas {
711 t.Errorf("expected: %d replicas, got: %d", test.expectReplicas, *rs2.Spec.Replicas)
712 }
713 }
714 }
715
716 func TestDefaultRequestIsNotSetForReplicaSet(t *testing.T) {
717 s := v1.PodSpec{}
718 s.Containers = []v1.Container{
719 {
720 Resources: v1.ResourceRequirements{
721 Limits: v1.ResourceList{
722 v1.ResourceCPU: resource.MustParse("100m"),
723 },
724 },
725 },
726 }
727 rs := &appsv1beta2.ReplicaSet{
728 Spec: appsv1beta2.ReplicaSetSpec{
729 Replicas: ptr.To[int32](3),
730 Template: v1.PodTemplateSpec{
731 ObjectMeta: metav1.ObjectMeta{
732 Labels: map[string]string{
733 "foo": "bar",
734 },
735 },
736 Spec: s,
737 },
738 },
739 }
740 output := roundTrip(t, runtime.Object(rs))
741 rs2 := output.(*appsv1beta2.ReplicaSet)
742 defaultRequest := rs2.Spec.Template.Spec.Containers[0].Resources.Requests
743 requestValue := defaultRequest[v1.ResourceCPU]
744 if requestValue.String() != "0" {
745 t.Errorf("Expected 0 request value, got: %s", requestValue.String())
746 }
747 }
748
749 func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
750 data, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(SchemeGroupVersion), obj)
751 if err != nil {
752 t.Errorf("%v\n %#v", err, obj)
753 return nil
754 }
755 obj2, err := runtime.Decode(legacyscheme.Codecs.UniversalDecoder(), data)
756 if err != nil {
757 t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
758 return nil
759 }
760 obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
761 err = legacyscheme.Scheme.Convert(obj2, obj3, nil)
762 if err != nil {
763 t.Errorf("%v\nSource: %#v", err, obj2)
764 return nil
765 }
766 return obj3
767 }
768
View as plain text