k8s.io/kubernetes@v1.29.3/pkg/apis/apps/v1beta2/defaults_test.go (about) 1 /* 2 Copyright 2017 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 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 { // Labels change/defaulting test. 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 { // Labels change/defaulting test. 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 { // OnDeleteDaemonSetStrategyType update strategy. 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 { // Custom unique label key. 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 }