...

Source file src/k8s.io/kubernetes/pkg/apis/apps/v1beta2/defaults_test.go

Documentation: k8s.io/kubernetes/pkg/apis/apps/v1beta2

     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:      &notTheDefaultPartition,
   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:      &notTheDefaultPartition,
   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