...

Source file src/k8s.io/kubernetes/pkg/apis/batch/v1/defaults_test.go

Documentation: k8s.io/kubernetes/pkg/apis/batch/v1

     1  /*
     2  Copyright 2016 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 v1_test
    18  
    19  import (
    20  	"math"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	batchv1 "k8s.io/api/batch/v1"
    26  	v1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    30  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    31  	"k8s.io/kubernetes/pkg/api/legacyscheme"
    32  	_ "k8s.io/kubernetes/pkg/apis/batch/install"
    33  	_ "k8s.io/kubernetes/pkg/apis/core/install"
    34  	"k8s.io/kubernetes/pkg/features"
    35  	"k8s.io/utils/pointer"
    36  
    37  	. "k8s.io/kubernetes/pkg/apis/batch/v1"
    38  )
    39  
    40  func TestSetDefaultJob(t *testing.T) {
    41  	defaultLabels := map[string]string{"default": "default"}
    42  	validPodTemplateSpec := v1.PodTemplateSpec{
    43  		ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
    44  	}
    45  	tests := map[string]struct {
    46  		original                   *batchv1.Job
    47  		expected                   *batchv1.Job
    48  		expectLabels               bool
    49  		enablePodReplacementPolicy bool
    50  	}{
    51  		"Pod failure policy with some field values unspecified -> set default values": {
    52  			original: &batchv1.Job{
    53  				Spec: batchv1.JobSpec{
    54  					Template: v1.PodTemplateSpec{
    55  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
    56  					},
    57  					PodFailurePolicy: &batchv1.PodFailurePolicy{
    58  						Rules: []batchv1.PodFailurePolicyRule{
    59  							{
    60  								Action: batchv1.PodFailurePolicyActionFailJob,
    61  								OnPodConditions: []batchv1.PodFailurePolicyOnPodConditionsPattern{
    62  									{
    63  										Type:   v1.DisruptionTarget,
    64  										Status: v1.ConditionTrue,
    65  									},
    66  									{
    67  										Type:   v1.PodConditionType("MemoryLimitExceeded"),
    68  										Status: v1.ConditionFalse,
    69  									},
    70  									{
    71  										Type: v1.PodConditionType("DiskLimitExceeded"),
    72  									},
    73  								},
    74  							},
    75  							{
    76  								Action: batchv1.PodFailurePolicyActionFailJob,
    77  								OnExitCodes: &batchv1.PodFailurePolicyOnExitCodesRequirement{
    78  									Operator: batchv1.PodFailurePolicyOnExitCodesOpIn,
    79  									Values:   []int32{1},
    80  								},
    81  							},
    82  							{
    83  								Action: batchv1.PodFailurePolicyActionFailJob,
    84  								OnPodConditions: []batchv1.PodFailurePolicyOnPodConditionsPattern{
    85  									{
    86  										Type: v1.DisruptionTarget,
    87  									},
    88  								},
    89  							},
    90  						},
    91  					},
    92  				},
    93  			},
    94  			expected: &batchv1.Job{
    95  				Spec: batchv1.JobSpec{
    96  					Completions:    pointer.Int32(1),
    97  					Parallelism:    pointer.Int32(1),
    98  					BackoffLimit:   pointer.Int32(6),
    99  					CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
   100  					Suspend:        pointer.Bool(false),
   101  					ManualSelector: pointer.Bool(false),
   102  					PodFailurePolicy: &batchv1.PodFailurePolicy{
   103  						Rules: []batchv1.PodFailurePolicyRule{
   104  							{
   105  								Action: batchv1.PodFailurePolicyActionFailJob,
   106  								OnPodConditions: []batchv1.PodFailurePolicyOnPodConditionsPattern{
   107  									{
   108  										Type:   v1.DisruptionTarget,
   109  										Status: v1.ConditionTrue,
   110  									},
   111  									{
   112  										Type:   v1.PodConditionType("MemoryLimitExceeded"),
   113  										Status: v1.ConditionFalse,
   114  									},
   115  									{
   116  										Type:   v1.PodConditionType("DiskLimitExceeded"),
   117  										Status: v1.ConditionTrue,
   118  									},
   119  								},
   120  							},
   121  							{
   122  								Action: batchv1.PodFailurePolicyActionFailJob,
   123  								OnExitCodes: &batchv1.PodFailurePolicyOnExitCodesRequirement{
   124  									Operator: batchv1.PodFailurePolicyOnExitCodesOpIn,
   125  									Values:   []int32{1},
   126  								},
   127  							},
   128  							{
   129  								Action: batchv1.PodFailurePolicyActionFailJob,
   130  								OnPodConditions: []batchv1.PodFailurePolicyOnPodConditionsPattern{
   131  									{
   132  										Type:   v1.DisruptionTarget,
   133  										Status: v1.ConditionTrue,
   134  									},
   135  								},
   136  							},
   137  						},
   138  					},
   139  				},
   140  			},
   141  			expectLabels: true,
   142  		},
   143  		"Pod failure policy and defaulting for pod replacement policy": {
   144  			original: &batchv1.Job{
   145  				Spec: batchv1.JobSpec{
   146  					Template: v1.PodTemplateSpec{
   147  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   148  					},
   149  					PodFailurePolicy: &batchv1.PodFailurePolicy{
   150  						Rules: []batchv1.PodFailurePolicyRule{
   151  							{
   152  								Action: batchv1.PodFailurePolicyActionFailJob,
   153  								OnExitCodes: &batchv1.PodFailurePolicyOnExitCodesRequirement{
   154  									Operator: batchv1.PodFailurePolicyOnExitCodesOpIn,
   155  									Values:   []int32{1},
   156  								},
   157  							},
   158  						},
   159  					},
   160  				},
   161  			},
   162  			expected: &batchv1.Job{
   163  				Spec: batchv1.JobSpec{
   164  					Completions:          pointer.Int32(1),
   165  					Parallelism:          pointer.Int32(1),
   166  					BackoffLimit:         pointer.Int32(6),
   167  					CompletionMode:       completionModePtr(batchv1.NonIndexedCompletion),
   168  					Suspend:              pointer.Bool(false),
   169  					PodReplacementPolicy: podReplacementPtr(batchv1.Failed),
   170  					ManualSelector:       pointer.Bool(false),
   171  					PodFailurePolicy: &batchv1.PodFailurePolicy{
   172  						Rules: []batchv1.PodFailurePolicyRule{
   173  							{
   174  								Action: batchv1.PodFailurePolicyActionFailJob,
   175  								OnExitCodes: &batchv1.PodFailurePolicyOnExitCodesRequirement{
   176  									Operator: batchv1.PodFailurePolicyOnExitCodesOpIn,
   177  									Values:   []int32{1},
   178  								},
   179  							},
   180  						},
   181  					},
   182  				},
   183  			},
   184  			expectLabels:               true,
   185  			enablePodReplacementPolicy: true,
   186  		},
   187  		"All unspecified and podReplacementPolicyEnabled -> sets all to default values": {
   188  			original: &batchv1.Job{
   189  				Spec: batchv1.JobSpec{
   190  					Template: v1.PodTemplateSpec{
   191  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   192  					},
   193  				},
   194  			},
   195  			expected: &batchv1.Job{
   196  				Spec: batchv1.JobSpec{
   197  					Completions:          pointer.Int32(1),
   198  					Parallelism:          pointer.Int32(1),
   199  					BackoffLimit:         pointer.Int32(6),
   200  					CompletionMode:       completionModePtr(batchv1.NonIndexedCompletion),
   201  					Suspend:              pointer.Bool(false),
   202  					PodReplacementPolicy: podReplacementPtr(batchv1.TerminatingOrFailed),
   203  					ManualSelector:       pointer.Bool(false),
   204  				},
   205  			},
   206  			expectLabels:               true,
   207  			enablePodReplacementPolicy: true,
   208  		},
   209  		"All unspecified -> sets all to default values": {
   210  			original: &batchv1.Job{
   211  				Spec: batchv1.JobSpec{
   212  					Template: v1.PodTemplateSpec{
   213  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   214  					},
   215  				},
   216  			},
   217  			expected: &batchv1.Job{
   218  				Spec: batchv1.JobSpec{
   219  					Completions:    pointer.Int32(1),
   220  					Parallelism:    pointer.Int32(1),
   221  					BackoffLimit:   pointer.Int32(6),
   222  					CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
   223  					Suspend:        pointer.Bool(false),
   224  					ManualSelector: pointer.Bool(false),
   225  				},
   226  			},
   227  			expectLabels: true,
   228  		},
   229  		"All unspecified, suspend job enabled -> sets all to default values": {
   230  			original: &batchv1.Job{
   231  				Spec: batchv1.JobSpec{
   232  					Template: v1.PodTemplateSpec{
   233  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   234  					},
   235  				},
   236  			},
   237  			expected: &batchv1.Job{
   238  				Spec: batchv1.JobSpec{
   239  					Completions:    pointer.Int32(1),
   240  					Parallelism:    pointer.Int32(1),
   241  					BackoffLimit:   pointer.Int32(6),
   242  					CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
   243  					Suspend:        pointer.Bool(false),
   244  					ManualSelector: pointer.Bool(false),
   245  				},
   246  			},
   247  			expectLabels: true,
   248  		},
   249  		"suspend set, everything else is defaulted": {
   250  			original: &batchv1.Job{
   251  				Spec: batchv1.JobSpec{
   252  					Suspend: pointer.Bool(true),
   253  					Template: v1.PodTemplateSpec{
   254  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   255  					},
   256  				},
   257  			},
   258  			expected: &batchv1.Job{
   259  				Spec: batchv1.JobSpec{
   260  					Completions:    pointer.Int32(1),
   261  					Parallelism:    pointer.Int32(1),
   262  					BackoffLimit:   pointer.Int32(6),
   263  					CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
   264  					Suspend:        pointer.Bool(true),
   265  					ManualSelector: pointer.Bool(false),
   266  				},
   267  			},
   268  			expectLabels: true,
   269  		},
   270  		"All unspecified -> all pointers are defaulted and no default labels": {
   271  			original: &batchv1.Job{
   272  				ObjectMeta: metav1.ObjectMeta{
   273  					Labels: map[string]string{"mylabel": "myvalue"},
   274  				},
   275  				Spec: batchv1.JobSpec{
   276  					Template: v1.PodTemplateSpec{
   277  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   278  					},
   279  				},
   280  			},
   281  			expected: &batchv1.Job{
   282  				Spec: batchv1.JobSpec{
   283  					Completions:    pointer.Int32(1),
   284  					Parallelism:    pointer.Int32(1),
   285  					BackoffLimit:   pointer.Int32(6),
   286  					CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
   287  					Suspend:        pointer.Bool(false),
   288  					ManualSelector: pointer.Bool(false),
   289  				},
   290  			},
   291  		},
   292  		"WQ: Parallelism explicitly 0 and completions unset -> BackoffLimit is defaulted": {
   293  			original: &batchv1.Job{
   294  				Spec: batchv1.JobSpec{
   295  					Parallelism: pointer.Int32(0),
   296  					Template: v1.PodTemplateSpec{
   297  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   298  					},
   299  				},
   300  			},
   301  			expected: &batchv1.Job{
   302  				Spec: batchv1.JobSpec{
   303  					Parallelism:    pointer.Int32(0),
   304  					BackoffLimit:   pointer.Int32(6),
   305  					CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
   306  					Suspend:        pointer.Bool(false),
   307  					ManualSelector: pointer.Bool(false),
   308  				},
   309  			},
   310  			expectLabels: true,
   311  		},
   312  		"WQ: Parallelism explicitly 2 and completions unset -> BackoffLimit is defaulted": {
   313  			original: &batchv1.Job{
   314  				Spec: batchv1.JobSpec{
   315  					Parallelism: pointer.Int32(2),
   316  					Template: v1.PodTemplateSpec{
   317  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   318  					},
   319  				},
   320  			},
   321  			expected: &batchv1.Job{
   322  				Spec: batchv1.JobSpec{
   323  					Parallelism:    pointer.Int32(2),
   324  					BackoffLimit:   pointer.Int32(6),
   325  					CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
   326  					Suspend:        pointer.Bool(false),
   327  					ManualSelector: pointer.Bool(false),
   328  				},
   329  			},
   330  			expectLabels: true,
   331  		},
   332  		"Completions explicitly 2 and others unset -> parallelism and BackoffLimit are defaulted": {
   333  			original: &batchv1.Job{
   334  				Spec: batchv1.JobSpec{
   335  					Completions: pointer.Int32(2),
   336  					Template: v1.PodTemplateSpec{
   337  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   338  					},
   339  				},
   340  			},
   341  			expected: &batchv1.Job{
   342  				Spec: batchv1.JobSpec{
   343  					Completions:    pointer.Int32(2),
   344  					Parallelism:    pointer.Int32(1),
   345  					BackoffLimit:   pointer.Int32(6),
   346  					CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
   347  					Suspend:        pointer.Bool(false),
   348  					ManualSelector: pointer.Bool(false),
   349  				},
   350  			},
   351  			expectLabels: true,
   352  		},
   353  		"BackoffLimit explicitly 5 and others unset -> parallelism and completions are defaulted": {
   354  			original: &batchv1.Job{
   355  				Spec: batchv1.JobSpec{
   356  					BackoffLimit: pointer.Int32(5),
   357  					Template: v1.PodTemplateSpec{
   358  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   359  					},
   360  				},
   361  			},
   362  			expected: &batchv1.Job{
   363  				Spec: batchv1.JobSpec{
   364  					Completions:    pointer.Int32(1),
   365  					Parallelism:    pointer.Int32(1),
   366  					BackoffLimit:   pointer.Int32(5),
   367  					CompletionMode: completionModePtr(batchv1.NonIndexedCompletion),
   368  					Suspend:        pointer.Bool(false),
   369  					ManualSelector: pointer.Bool(false),
   370  				},
   371  			},
   372  			expectLabels: true,
   373  		},
   374  		"All set -> no change": {
   375  			original: &batchv1.Job{
   376  				Spec: batchv1.JobSpec{
   377  					Completions:          pointer.Int32(8),
   378  					Parallelism:          pointer.Int32(9),
   379  					BackoffLimit:         pointer.Int32(10),
   380  					CompletionMode:       completionModePtr(batchv1.NonIndexedCompletion),
   381  					Suspend:              pointer.Bool(false),
   382  					PodReplacementPolicy: podReplacementPtr(batchv1.TerminatingOrFailed),
   383  					ManualSelector:       pointer.Bool(false),
   384  					Template: v1.PodTemplateSpec{
   385  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   386  					},
   387  				},
   388  			},
   389  			expected: &batchv1.Job{
   390  				Spec: batchv1.JobSpec{
   391  					Completions:          pointer.Int32(8),
   392  					Parallelism:          pointer.Int32(9),
   393  					BackoffLimit:         pointer.Int32(10),
   394  					CompletionMode:       completionModePtr(batchv1.NonIndexedCompletion),
   395  					Suspend:              pointer.Bool(false),
   396  					PodReplacementPolicy: podReplacementPtr(batchv1.TerminatingOrFailed),
   397  					ManualSelector:       pointer.Bool(false),
   398  					Template: v1.PodTemplateSpec{
   399  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   400  					},
   401  				},
   402  			},
   403  			expectLabels: true,
   404  		},
   405  		"All set, flipped -> no change": {
   406  			original: &batchv1.Job{
   407  				Spec: batchv1.JobSpec{
   408  					Completions:          pointer.Int32(11),
   409  					Parallelism:          pointer.Int32(10),
   410  					BackoffLimit:         pointer.Int32(9),
   411  					CompletionMode:       completionModePtr(batchv1.IndexedCompletion),
   412  					Suspend:              pointer.Bool(true),
   413  					PodReplacementPolicy: podReplacementPtr(batchv1.Failed),
   414  					ManualSelector:       pointer.Bool(true),
   415  					Template: v1.PodTemplateSpec{
   416  						ObjectMeta: metav1.ObjectMeta{Labels: defaultLabels},
   417  					},
   418  				},
   419  			},
   420  			expected: &batchv1.Job{
   421  				Spec: batchv1.JobSpec{
   422  					Completions:          pointer.Int32(11),
   423  					Parallelism:          pointer.Int32(10),
   424  					BackoffLimit:         pointer.Int32(9),
   425  					CompletionMode:       completionModePtr(batchv1.IndexedCompletion),
   426  					Suspend:              pointer.Bool(true),
   427  					PodReplacementPolicy: podReplacementPtr(batchv1.Failed),
   428  					ManualSelector:       pointer.Bool(true),
   429  				},
   430  			},
   431  			expectLabels: true,
   432  		},
   433  		"BackoffLimitPerIndex specified, but no BackoffLimit -> default BackoffLimit to max int32": {
   434  			original: &batchv1.Job{
   435  				Spec: batchv1.JobSpec{
   436  					Completions:          pointer.Int32(11),
   437  					Parallelism:          pointer.Int32(10),
   438  					BackoffLimitPerIndex: pointer.Int32(1),
   439  					CompletionMode:       completionModePtr(batchv1.IndexedCompletion),
   440  					Template:             validPodTemplateSpec,
   441  					Suspend:              pointer.Bool(true),
   442  					ManualSelector:       pointer.Bool(false),
   443  				},
   444  			},
   445  			expected: &batchv1.Job{
   446  				Spec: batchv1.JobSpec{
   447  					Completions:          pointer.Int32(11),
   448  					Parallelism:          pointer.Int32(10),
   449  					BackoffLimit:         pointer.Int32(math.MaxInt32),
   450  					BackoffLimitPerIndex: pointer.Int32(1),
   451  					CompletionMode:       completionModePtr(batchv1.IndexedCompletion),
   452  					Template:             validPodTemplateSpec,
   453  					Suspend:              pointer.Bool(true),
   454  					ManualSelector:       pointer.Bool(false),
   455  				},
   456  			},
   457  			expectLabels: true,
   458  		},
   459  		"BackoffLimitPerIndex and BackoffLimit specified -> no change": {
   460  			original: &batchv1.Job{
   461  				Spec: batchv1.JobSpec{
   462  					Completions:          pointer.Int32(11),
   463  					Parallelism:          pointer.Int32(10),
   464  					BackoffLimit:         pointer.Int32(3),
   465  					BackoffLimitPerIndex: pointer.Int32(1),
   466  					CompletionMode:       completionModePtr(batchv1.IndexedCompletion),
   467  					Template:             validPodTemplateSpec,
   468  					Suspend:              pointer.Bool(true),
   469  					ManualSelector:       pointer.Bool(true),
   470  				},
   471  			},
   472  			expected: &batchv1.Job{
   473  				Spec: batchv1.JobSpec{
   474  					Completions:          pointer.Int32(11),
   475  					Parallelism:          pointer.Int32(10),
   476  					BackoffLimit:         pointer.Int32(3),
   477  					BackoffLimitPerIndex: pointer.Int32(1),
   478  					CompletionMode:       completionModePtr(batchv1.IndexedCompletion),
   479  					Template:             validPodTemplateSpec,
   480  					Suspend:              pointer.Bool(true),
   481  					ManualSelector:       pointer.Bool(true),
   482  				},
   483  			},
   484  			expectLabels: true,
   485  		},
   486  	}
   487  
   488  	for name, test := range tests {
   489  		t.Run(name, func(t *testing.T) {
   490  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.JobPodReplacementPolicy, test.enablePodReplacementPolicy)()
   491  			original := test.original
   492  			expected := test.expected
   493  			obj2 := roundTrip(t, runtime.Object(original))
   494  			actual, ok := obj2.(*batchv1.Job)
   495  			if !ok {
   496  				t.Fatalf("Unexpected object: %v", actual)
   497  			}
   498  
   499  			if diff := cmp.Diff(expected.Spec.Suspend, actual.Spec.Suspend); diff != "" {
   500  				t.Errorf(".spec.suspend does not match; -want,+got:\n%s", diff)
   501  			}
   502  			validateDefaultInt32(t, "Completions", actual.Spec.Completions, expected.Spec.Completions)
   503  			validateDefaultInt32(t, "Parallelism", actual.Spec.Parallelism, expected.Spec.Parallelism)
   504  			validateDefaultInt32(t, "BackoffLimit", actual.Spec.BackoffLimit, expected.Spec.BackoffLimit)
   505  
   506  			if diff := cmp.Diff(expected.Spec.PodFailurePolicy, actual.Spec.PodFailurePolicy); diff != "" {
   507  				t.Errorf("unexpected diff in errors (-want, +got):\n%s", diff)
   508  			}
   509  			if test.expectLabels != reflect.DeepEqual(actual.Labels, actual.Spec.Template.Labels) {
   510  				if test.expectLabels {
   511  					t.Errorf("Expected labels: %v, got: %v", actual.Spec.Template.Labels, actual.Labels)
   512  				} else {
   513  					t.Errorf("Unexpected equality: %v", actual.Labels)
   514  				}
   515  			}
   516  			if diff := cmp.Diff(expected.Spec.CompletionMode, actual.Spec.CompletionMode); diff != "" {
   517  				t.Errorf("Unexpected CompletionMode (-want,+got):\n%s", diff)
   518  			}
   519  			if diff := cmp.Diff(expected.Spec.PodReplacementPolicy, actual.Spec.PodReplacementPolicy); diff != "" {
   520  				t.Errorf("Unexpected PodReplacementPolicy (-want,+got):\n%s", diff)
   521  			}
   522  			if diff := cmp.Diff(expected.Spec.ManualSelector, actual.Spec.ManualSelector); diff != "" {
   523  				t.Errorf("Unexpected ManualSelector (-want,+got):\n%s", diff)
   524  			}
   525  		})
   526  	}
   527  }
   528  
   529  func validateDefaultInt32(t *testing.T, field string, actual *int32, expected *int32) {
   530  	if (actual == nil) != (expected == nil) {
   531  		t.Errorf("Got different *%s than expected: %v %v", field, actual, expected)
   532  	}
   533  	if actual != nil && expected != nil {
   534  		if *actual != *expected {
   535  			t.Errorf("Got different %s than expected: %d %d", field, *actual, *expected)
   536  		}
   537  	}
   538  }
   539  
   540  func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
   541  	data, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(SchemeGroupVersion), obj)
   542  	if err != nil {
   543  		t.Errorf("%v\n %#v", err, obj)
   544  		return nil
   545  	}
   546  	obj2, err := runtime.Decode(legacyscheme.Codecs.UniversalDecoder(), data)
   547  	if err != nil {
   548  		t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
   549  		return nil
   550  	}
   551  	obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
   552  	err = legacyscheme.Scheme.Convert(obj2, obj3, nil)
   553  	if err != nil {
   554  		t.Errorf("%v\nSource: %#v", err, obj2)
   555  		return nil
   556  	}
   557  	return obj3
   558  }
   559  
   560  func TestSetDefaultCronJob(t *testing.T) {
   561  	tests := map[string]struct {
   562  		original *batchv1.CronJob
   563  		expected *batchv1.CronJob
   564  	}{
   565  		"empty batchv1.CronJob should default batchv1.ConcurrencyPolicy and Suspend": {
   566  			original: &batchv1.CronJob{},
   567  			expected: &batchv1.CronJob{
   568  				Spec: batchv1.CronJobSpec{
   569  					ConcurrencyPolicy:          batchv1.AllowConcurrent,
   570  					Suspend:                    pointer.Bool(false),
   571  					SuccessfulJobsHistoryLimit: pointer.Int32(3),
   572  					FailedJobsHistoryLimit:     pointer.Int32(1),
   573  				},
   574  			},
   575  		},
   576  		"set fields should not be defaulted": {
   577  			original: &batchv1.CronJob{
   578  				Spec: batchv1.CronJobSpec{
   579  					ConcurrencyPolicy:          batchv1.ForbidConcurrent,
   580  					Suspend:                    pointer.Bool(true),
   581  					SuccessfulJobsHistoryLimit: pointer.Int32(5),
   582  					FailedJobsHistoryLimit:     pointer.Int32(5),
   583  				},
   584  			},
   585  			expected: &batchv1.CronJob{
   586  				Spec: batchv1.CronJobSpec{
   587  					ConcurrencyPolicy:          batchv1.ForbidConcurrent,
   588  					Suspend:                    pointer.Bool(true),
   589  					SuccessfulJobsHistoryLimit: pointer.Int32(5),
   590  					FailedJobsHistoryLimit:     pointer.Int32(5),
   591  				},
   592  			},
   593  		},
   594  	}
   595  
   596  	for name, test := range tests {
   597  		original := test.original
   598  		expected := test.expected
   599  		obj2 := roundTrip(t, runtime.Object(original))
   600  		actual, ok := obj2.(*batchv1.CronJob)
   601  		if !ok {
   602  			t.Errorf("%s: unexpected object: %v", name, actual)
   603  			t.FailNow()
   604  		}
   605  		if actual.Spec.ConcurrencyPolicy != expected.Spec.ConcurrencyPolicy {
   606  			t.Errorf("%s: got different concurrencyPolicy than expected: %v %v", name, actual.Spec.ConcurrencyPolicy, expected.Spec.ConcurrencyPolicy)
   607  		}
   608  		if *actual.Spec.Suspend != *expected.Spec.Suspend {
   609  			t.Errorf("%s: got different suspend than expected: %v %v", name, *actual.Spec.Suspend, *expected.Spec.Suspend)
   610  		}
   611  		if *actual.Spec.SuccessfulJobsHistoryLimit != *expected.Spec.SuccessfulJobsHistoryLimit {
   612  			t.Errorf("%s: got different successfulJobsHistoryLimit than expected: %v %v", name, *actual.Spec.SuccessfulJobsHistoryLimit, *expected.Spec.SuccessfulJobsHistoryLimit)
   613  		}
   614  		if *actual.Spec.FailedJobsHistoryLimit != *expected.Spec.FailedJobsHistoryLimit {
   615  			t.Errorf("%s: got different failedJobsHistoryLimit than expected: %v %v", name, *actual.Spec.FailedJobsHistoryLimit, *expected.Spec.FailedJobsHistoryLimit)
   616  		}
   617  	}
   618  }
   619  
   620  func completionModePtr(m batchv1.CompletionMode) *batchv1.CompletionMode {
   621  	return &m
   622  }
   623  
   624  func podReplacementPtr(m batchv1.PodReplacementPolicy) *batchv1.PodReplacementPolicy {
   625  	return &m
   626  }
   627  

View as plain text