...

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

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

     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 v1beta1_test
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	appsv1beta1 "k8s.io/api/apps/v1beta1"
    24  
    25  	v1 "k8s.io/api/core/v1"
    26  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    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/v1beta1"
    35  	_ "k8s.io/kubernetes/pkg/apis/core/install"
    36  	"k8s.io/kubernetes/pkg/features"
    37  	"k8s.io/utils/ptr"
    38  )
    39  
    40  func TestSetDefaultDeployment(t *testing.T) {
    41  	defaultIntOrString := intstr.FromString("25%")
    42  	differentIntOrString := intstr.FromInt32(5)
    43  	period := int64(v1.DefaultTerminationGracePeriodSeconds)
    44  	defaultTemplate := v1.PodTemplateSpec{
    45  		Spec: v1.PodSpec{
    46  			DNSPolicy:                     v1.DNSClusterFirst,
    47  			RestartPolicy:                 v1.RestartPolicyAlways,
    48  			SecurityContext:               &v1.PodSecurityContext{},
    49  			TerminationGracePeriodSeconds: &period,
    50  			SchedulerName:                 v1.DefaultSchedulerName,
    51  		},
    52  	}
    53  	tests := []struct {
    54  		original *appsv1beta1.Deployment
    55  		expected *appsv1beta1.Deployment
    56  	}{
    57  		{
    58  			original: &appsv1beta1.Deployment{},
    59  			expected: &appsv1beta1.Deployment{
    60  				Spec: appsv1beta1.DeploymentSpec{
    61  					Replicas: ptr.To[int32](1),
    62  					Strategy: appsv1beta1.DeploymentStrategy{
    63  						Type: appsv1beta1.RollingUpdateDeploymentStrategyType,
    64  						RollingUpdate: &appsv1beta1.RollingUpdateDeployment{
    65  							MaxSurge:       &defaultIntOrString,
    66  							MaxUnavailable: &defaultIntOrString,
    67  						},
    68  					},
    69  					RevisionHistoryLimit:    ptr.To[int32](2),
    70  					ProgressDeadlineSeconds: ptr.To[int32](600),
    71  					Template:                defaultTemplate,
    72  				},
    73  			},
    74  		},
    75  		{
    76  			original: &appsv1beta1.Deployment{
    77  				Spec: appsv1beta1.DeploymentSpec{
    78  					Replicas: ptr.To[int32](5),
    79  					Strategy: appsv1beta1.DeploymentStrategy{
    80  						RollingUpdate: &appsv1beta1.RollingUpdateDeployment{
    81  							MaxSurge: &differentIntOrString,
    82  						},
    83  					},
    84  				},
    85  			},
    86  			expected: &appsv1beta1.Deployment{
    87  				Spec: appsv1beta1.DeploymentSpec{
    88  					Replicas: ptr.To[int32](5),
    89  					Strategy: appsv1beta1.DeploymentStrategy{
    90  						Type: appsv1beta1.RollingUpdateDeploymentStrategyType,
    91  						RollingUpdate: &appsv1beta1.RollingUpdateDeployment{
    92  							MaxSurge:       &differentIntOrString,
    93  							MaxUnavailable: &defaultIntOrString,
    94  						},
    95  					},
    96  					RevisionHistoryLimit:    ptr.To[int32](2),
    97  					ProgressDeadlineSeconds: ptr.To[int32](600),
    98  					Template:                defaultTemplate,
    99  				},
   100  			},
   101  		},
   102  		{
   103  			original: &appsv1beta1.Deployment{
   104  				Spec: appsv1beta1.DeploymentSpec{
   105  					Replicas: ptr.To[int32](3),
   106  					Strategy: appsv1beta1.DeploymentStrategy{
   107  						Type:          appsv1beta1.RollingUpdateDeploymentStrategyType,
   108  						RollingUpdate: nil,
   109  					},
   110  				},
   111  			},
   112  			expected: &appsv1beta1.Deployment{
   113  				Spec: appsv1beta1.DeploymentSpec{
   114  					Replicas: ptr.To[int32](3),
   115  					Strategy: appsv1beta1.DeploymentStrategy{
   116  						Type: appsv1beta1.RollingUpdateDeploymentStrategyType,
   117  						RollingUpdate: &appsv1beta1.RollingUpdateDeployment{
   118  							MaxSurge:       &defaultIntOrString,
   119  							MaxUnavailable: &defaultIntOrString,
   120  						},
   121  					},
   122  					RevisionHistoryLimit:    ptr.To[int32](2),
   123  					ProgressDeadlineSeconds: ptr.To[int32](600),
   124  					Template:                defaultTemplate,
   125  				},
   126  			},
   127  		},
   128  		{
   129  			original: &appsv1beta1.Deployment{
   130  				Spec: appsv1beta1.DeploymentSpec{
   131  					Replicas: ptr.To[int32](5),
   132  					Strategy: appsv1beta1.DeploymentStrategy{
   133  						Type: appsv1beta1.RecreateDeploymentStrategyType,
   134  					},
   135  					RevisionHistoryLimit: ptr.To[int32](0),
   136  				},
   137  			},
   138  			expected: &appsv1beta1.Deployment{
   139  				Spec: appsv1beta1.DeploymentSpec{
   140  					Replicas: ptr.To[int32](5),
   141  					Strategy: appsv1beta1.DeploymentStrategy{
   142  						Type: appsv1beta1.RecreateDeploymentStrategyType,
   143  					},
   144  					RevisionHistoryLimit:    ptr.To[int32](0),
   145  					ProgressDeadlineSeconds: ptr.To[int32](600),
   146  					Template:                defaultTemplate,
   147  				},
   148  			},
   149  		},
   150  		{
   151  			original: &appsv1beta1.Deployment{
   152  				Spec: appsv1beta1.DeploymentSpec{
   153  					Replicas: ptr.To[int32](5),
   154  					Strategy: appsv1beta1.DeploymentStrategy{
   155  						Type: appsv1beta1.RecreateDeploymentStrategyType,
   156  					},
   157  					ProgressDeadlineSeconds: ptr.To[int32](30),
   158  					RevisionHistoryLimit:    ptr.To[int32](2),
   159  				},
   160  			},
   161  			expected: &appsv1beta1.Deployment{
   162  				Spec: appsv1beta1.DeploymentSpec{
   163  					Replicas: ptr.To[int32](5),
   164  					Strategy: appsv1beta1.DeploymentStrategy{
   165  						Type: appsv1beta1.RecreateDeploymentStrategyType,
   166  					},
   167  					ProgressDeadlineSeconds: ptr.To[int32](30),
   168  					RevisionHistoryLimit:    ptr.To[int32](2),
   169  					Template:                defaultTemplate,
   170  				},
   171  			},
   172  		},
   173  	}
   174  
   175  	for _, test := range tests {
   176  		original := test.original
   177  		expected := test.expected
   178  		obj2 := roundTrip(t, runtime.Object(original))
   179  		got, ok := obj2.(*appsv1beta1.Deployment)
   180  		if !ok {
   181  			t.Errorf("unexpected object: %v", got)
   182  			t.FailNow()
   183  		}
   184  		if !apiequality.Semantic.DeepEqual(got.Spec, expected.Spec) {
   185  			t.Errorf("object mismatch!\nexpected:\n\t%+v\ngot:\n\t%+v", got.Spec, expected.Spec)
   186  		}
   187  	}
   188  }
   189  
   190  func TestDefaultDeploymentAvailability(t *testing.T) {
   191  	d := roundTrip(t, runtime.Object(&appsv1beta1.Deployment{})).(*appsv1beta1.Deployment)
   192  
   193  	maxUnavailable, err := intstr.GetScaledValueFromIntOrPercent(d.Spec.Strategy.RollingUpdate.MaxUnavailable, int(*(d.Spec.Replicas)), false)
   194  	if err != nil {
   195  		t.Fatalf("unexpected error: %v", err)
   196  	}
   197  
   198  	if *(d.Spec.Replicas)-int32(maxUnavailable) <= 0 {
   199  		t.Fatalf("the default value of maxUnavailable can lead to no active replicas during rolling update")
   200  	}
   201  }
   202  
   203  func TestSetDefaultStatefulSet(t *testing.T) {
   204  	defaultLabels := map[string]string{"foo": "bar"}
   205  	var defaultPartition int32 = 0
   206  	var notTheDefaultPartition int32 = 42
   207  	var defaultReplicas int32 = 1
   208  
   209  	period := int64(v1.DefaultTerminationGracePeriodSeconds)
   210  	defaultTemplate := v1.PodTemplateSpec{
   211  		Spec: v1.PodSpec{
   212  			DNSPolicy:                     v1.DNSClusterFirst,
   213  			RestartPolicy:                 v1.RestartPolicyAlways,
   214  			SecurityContext:               &v1.PodSecurityContext{},
   215  			TerminationGracePeriodSeconds: &period,
   216  			SchedulerName:                 v1.DefaultSchedulerName,
   217  		},
   218  		ObjectMeta: metav1.ObjectMeta{
   219  			Labels: defaultLabels,
   220  		},
   221  	}
   222  
   223  	tests := []struct {
   224  		name                        string
   225  		original                    *appsv1beta1.StatefulSet
   226  		expected                    *appsv1beta1.StatefulSet
   227  		enableMaxUnavailablePolicy  bool
   228  		enableStatefulSetAutoDelete bool
   229  	}{
   230  		{
   231  			name: "labels and default update strategy",
   232  			original: &appsv1beta1.StatefulSet{
   233  				Spec: appsv1beta1.StatefulSetSpec{
   234  					Template: defaultTemplate,
   235  				},
   236  			},
   237  			expected: &appsv1beta1.StatefulSet{
   238  				Spec: appsv1beta1.StatefulSetSpec{
   239  					Replicas:            &defaultReplicas,
   240  					MinReadySeconds:     int32(0),
   241  					Template:            defaultTemplate,
   242  					PodManagementPolicy: appsv1beta1.OrderedReadyPodManagement,
   243  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   244  						Type:          appsv1beta1.OnDeleteStatefulSetStrategyType,
   245  						RollingUpdate: nil,
   246  					},
   247  					RevisionHistoryLimit: ptr.To[int32](10),
   248  					Selector: &metav1.LabelSelector{
   249  						MatchLabels:      map[string]string{"foo": "bar"},
   250  						MatchExpressions: []metav1.LabelSelectorRequirement{},
   251  					},
   252  				},
   253  			},
   254  		},
   255  		{
   256  			name: "Alternate update strategy",
   257  			original: &appsv1beta1.StatefulSet{
   258  				Spec: appsv1beta1.StatefulSetSpec{
   259  					Template: defaultTemplate,
   260  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   261  						Type: appsv1beta1.RollingUpdateStatefulSetStrategyType,
   262  					},
   263  				},
   264  			},
   265  			expected: &appsv1beta1.StatefulSet{
   266  				Spec: appsv1beta1.StatefulSetSpec{
   267  					Replicas:            &defaultReplicas,
   268  					MinReadySeconds:     int32(0),
   269  					Template:            defaultTemplate,
   270  					PodManagementPolicy: appsv1beta1.OrderedReadyPodManagement,
   271  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   272  						Type:          appsv1beta1.RollingUpdateStatefulSetStrategyType,
   273  						RollingUpdate: nil,
   274  					},
   275  					RevisionHistoryLimit: ptr.To[int32](10),
   276  					Selector: &metav1.LabelSelector{
   277  						MatchLabels:      map[string]string{"foo": "bar"},
   278  						MatchExpressions: []metav1.LabelSelectorRequirement{},
   279  					},
   280  				},
   281  			},
   282  		},
   283  		{
   284  			name: "Parallel pod management policy.",
   285  			original: &appsv1beta1.StatefulSet{
   286  				Spec: appsv1beta1.StatefulSetSpec{
   287  					Template:            defaultTemplate,
   288  					PodManagementPolicy: appsv1beta1.ParallelPodManagement,
   289  				},
   290  			},
   291  			expected: &appsv1beta1.StatefulSet{
   292  				Spec: appsv1beta1.StatefulSetSpec{
   293  					Replicas:            &defaultReplicas,
   294  					MinReadySeconds:     int32(0),
   295  					Template:            defaultTemplate,
   296  					PodManagementPolicy: appsv1beta1.ParallelPodManagement,
   297  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   298  						Type:          appsv1beta1.OnDeleteStatefulSetStrategyType,
   299  						RollingUpdate: nil,
   300  					},
   301  					RevisionHistoryLimit: ptr.To[int32](10),
   302  					Selector: &metav1.LabelSelector{
   303  						MatchLabels:      map[string]string{"foo": "bar"},
   304  						MatchExpressions: []metav1.LabelSelectorRequirement{},
   305  					},
   306  				},
   307  			},
   308  		},
   309  		{
   310  			name: "MaxUnavailable disabled, with maxUnavailable not specified",
   311  			original: &appsv1beta1.StatefulSet{
   312  				Spec: appsv1beta1.StatefulSetSpec{
   313  					Template: defaultTemplate,
   314  				},
   315  			},
   316  			expected: &appsv1beta1.StatefulSet{
   317  				Spec: appsv1beta1.StatefulSetSpec{
   318  					Replicas:            &defaultReplicas,
   319  					Template:            defaultTemplate,
   320  					PodManagementPolicy: appsv1beta1.OrderedReadyPodManagement,
   321  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   322  						Type:          appsv1beta1.OnDeleteStatefulSetStrategyType,
   323  						RollingUpdate: nil,
   324  					},
   325  					RevisionHistoryLimit: ptr.To[int32](10),
   326  					Selector: &metav1.LabelSelector{
   327  						MatchLabels:      map[string]string{"foo": "bar"},
   328  						MatchExpressions: []metav1.LabelSelectorRequirement{},
   329  					},
   330  				},
   331  			},
   332  			enableMaxUnavailablePolicy: false,
   333  		},
   334  		{
   335  			name: "MaxUnavailable disabled, with default maxUnavailable specified",
   336  			original: &appsv1beta1.StatefulSet{
   337  				Spec: appsv1beta1.StatefulSetSpec{
   338  					Template: defaultTemplate,
   339  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   340  						RollingUpdate: &appsv1beta1.RollingUpdateStatefulSetStrategy{
   341  							Partition:      &defaultPartition,
   342  							MaxUnavailable: ptr.To(intstr.FromInt32(1)),
   343  						},
   344  					},
   345  				},
   346  			},
   347  			expected: &appsv1beta1.StatefulSet{
   348  				Spec: appsv1beta1.StatefulSetSpec{
   349  					Replicas:            &defaultReplicas,
   350  					Template:            defaultTemplate,
   351  					PodManagementPolicy: appsv1beta1.OrderedReadyPodManagement,
   352  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   353  						Type: appsv1beta1.OnDeleteStatefulSetStrategyType,
   354  						RollingUpdate: &appsv1beta1.RollingUpdateStatefulSetStrategy{
   355  							Partition:      ptr.To[int32](0),
   356  							MaxUnavailable: ptr.To(intstr.FromInt32(1)),
   357  						},
   358  					},
   359  					RevisionHistoryLimit: ptr.To[int32](10),
   360  					Selector: &metav1.LabelSelector{
   361  						MatchLabels:      map[string]string{"foo": "bar"},
   362  						MatchExpressions: []metav1.LabelSelectorRequirement{},
   363  					},
   364  				},
   365  			},
   366  			enableMaxUnavailablePolicy: false,
   367  		},
   368  		{
   369  			name: "MaxUnavailable disabled, with non default maxUnavailable specified",
   370  			original: &appsv1beta1.StatefulSet{
   371  				Spec: appsv1beta1.StatefulSetSpec{
   372  					Template: defaultTemplate,
   373  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   374  						RollingUpdate: &appsv1beta1.RollingUpdateStatefulSetStrategy{
   375  							Partition:      &notTheDefaultPartition,
   376  							MaxUnavailable: ptr.To(intstr.FromInt32(3)),
   377  						},
   378  					},
   379  				},
   380  			},
   381  			expected: &appsv1beta1.StatefulSet{
   382  				Spec: appsv1beta1.StatefulSetSpec{
   383  					Replicas:            &defaultReplicas,
   384  					Template:            defaultTemplate,
   385  					PodManagementPolicy: appsv1beta1.OrderedReadyPodManagement,
   386  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   387  						Type: appsv1beta1.OnDeleteStatefulSetStrategyType,
   388  						RollingUpdate: &appsv1beta1.RollingUpdateStatefulSetStrategy{
   389  							Partition:      ptr.To[int32](42),
   390  							MaxUnavailable: ptr.To(intstr.FromInt32(3)),
   391  						},
   392  					},
   393  					RevisionHistoryLimit: ptr.To[int32](10),
   394  					Selector: &metav1.LabelSelector{
   395  						MatchLabels:      map[string]string{"foo": "bar"},
   396  						MatchExpressions: []metav1.LabelSelectorRequirement{},
   397  					},
   398  				},
   399  			},
   400  			enableMaxUnavailablePolicy: false,
   401  		},
   402  		{
   403  			name: "MaxUnavailable enabled, with no maxUnavailable specified",
   404  			original: &appsv1beta1.StatefulSet{
   405  				Spec: appsv1beta1.StatefulSetSpec{
   406  					Template: defaultTemplate,
   407  				},
   408  			},
   409  			expected: &appsv1beta1.StatefulSet{
   410  				Spec: appsv1beta1.StatefulSetSpec{
   411  					Replicas:            &defaultReplicas,
   412  					Template:            defaultTemplate,
   413  					PodManagementPolicy: appsv1beta1.OrderedReadyPodManagement,
   414  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   415  						Type:          appsv1beta1.OnDeleteStatefulSetStrategyType,
   416  						RollingUpdate: nil,
   417  					},
   418  					RevisionHistoryLimit: ptr.To[int32](10),
   419  					Selector: &metav1.LabelSelector{
   420  						MatchLabels:      map[string]string{"foo": "bar"},
   421  						MatchExpressions: []metav1.LabelSelectorRequirement{},
   422  					},
   423  				},
   424  			},
   425  			enableMaxUnavailablePolicy: true,
   426  		},
   427  		{
   428  			name: "MaxUnavailable enabled, with non default maxUnavailable specified",
   429  			original: &appsv1beta1.StatefulSet{
   430  				Spec: appsv1beta1.StatefulSetSpec{
   431  					Template: defaultTemplate,
   432  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   433  						RollingUpdate: &appsv1beta1.RollingUpdateStatefulSetStrategy{
   434  							Partition:      &notTheDefaultPartition,
   435  							MaxUnavailable: ptr.To(intstr.FromInt32(3)),
   436  						},
   437  					},
   438  				},
   439  			},
   440  			expected: &appsv1beta1.StatefulSet{
   441  				Spec: appsv1beta1.StatefulSetSpec{
   442  					Replicas:            &defaultReplicas,
   443  					Template:            defaultTemplate,
   444  					PodManagementPolicy: appsv1beta1.OrderedReadyPodManagement,
   445  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   446  						Type: appsv1beta1.OnDeleteStatefulSetStrategyType,
   447  						RollingUpdate: &appsv1beta1.RollingUpdateStatefulSetStrategy{
   448  							Partition:      ptr.To[int32](42),
   449  							MaxUnavailable: ptr.To(intstr.FromInt32(3)),
   450  						},
   451  					},
   452  					RevisionHistoryLimit: ptr.To[int32](10),
   453  					Selector: &metav1.LabelSelector{
   454  						MatchLabels:      map[string]string{"foo": "bar"},
   455  						MatchExpressions: []metav1.LabelSelectorRequirement{},
   456  					},
   457  				},
   458  			},
   459  			enableMaxUnavailablePolicy: true,
   460  		},
   461  		{
   462  			name: "StatefulSetAutoDeletePVC enabled",
   463  			original: &appsv1beta1.StatefulSet{
   464  				Spec: appsv1beta1.StatefulSetSpec{
   465  					Template: defaultTemplate,
   466  				},
   467  			},
   468  			expected: &appsv1beta1.StatefulSet{
   469  				Spec: appsv1beta1.StatefulSetSpec{
   470  					Replicas:            &defaultReplicas,
   471  					Template:            defaultTemplate,
   472  					PodManagementPolicy: appsv1beta1.OrderedReadyPodManagement,
   473  					UpdateStrategy: appsv1beta1.StatefulSetUpdateStrategy{
   474  						Type:          appsv1beta1.OnDeleteStatefulSetStrategyType,
   475  						RollingUpdate: nil,
   476  					},
   477  					RevisionHistoryLimit: ptr.To[int32](10),
   478  					PersistentVolumeClaimRetentionPolicy: &appsv1beta1.StatefulSetPersistentVolumeClaimRetentionPolicy{
   479  						WhenDeleted: appsv1beta1.RetainPersistentVolumeClaimRetentionPolicyType,
   480  						WhenScaled:  appsv1beta1.RetainPersistentVolumeClaimRetentionPolicyType,
   481  					},
   482  					Selector: &metav1.LabelSelector{
   483  						MatchLabels:      map[string]string{"foo": "bar"},
   484  						MatchExpressions: []metav1.LabelSelectorRequirement{},
   485  					},
   486  				},
   487  			},
   488  			enableStatefulSetAutoDelete: true,
   489  		},
   490  	}
   491  
   492  	for _, test := range tests {
   493  		test := test
   494  		t.Run(test.name, func(t *testing.T) {
   495  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MaxUnavailableStatefulSet, test.enableMaxUnavailablePolicy)()
   496  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StatefulSetAutoDeletePVC, test.enableStatefulSetAutoDelete)()
   497  			obj2 := roundTrip(t, runtime.Object(test.original))
   498  			got, ok := obj2.(*appsv1beta1.StatefulSet)
   499  			if !ok {
   500  				t.Errorf("unexpected object: %v", got)
   501  				t.FailNow()
   502  			}
   503  			if !apiequality.Semantic.DeepEqual(got.Spec, test.expected.Spec) {
   504  				t.Errorf("got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", got.Spec, test.expected.Spec)
   505  			}
   506  		})
   507  	}
   508  }
   509  
   510  func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
   511  	data, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(SchemeGroupVersion), obj)
   512  	if err != nil {
   513  		t.Errorf("%v\n %#v", err, obj)
   514  		return nil
   515  	}
   516  	obj2, err := runtime.Decode(legacyscheme.Codecs.UniversalDecoder(), data)
   517  	if err != nil {
   518  		t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
   519  		return nil
   520  	}
   521  	obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
   522  	err = legacyscheme.Scheme.Convert(obj2, obj3, nil)
   523  	if err != nil {
   524  		t.Errorf("%v\nSource: %#v", err, obj2)
   525  		return nil
   526  	}
   527  	return obj3
   528  }
   529  

View as plain text