} } <del> // TODO(#111514): refactor by spliting into dedicated test functions func TestJobStrategy(t *testing.T) { ctx := genericapirequest.NewDefaultContext() if !Strategy.NamespaceScoped() { t.Errorf("Job must be namespace scoped") } if Strategy.AllowCreateOnUpdate() { t.Errorf("Job should not allow create on update") } validSelector := &metav1.LabelSelector{ MatchLabels: map[string]string{"a": "b"}, } validPodTemplateSpec := api.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: validSelector.MatchLabels, }, Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyOnFailure, DNSPolicy:     api.DNSClusterFirst, Containers:    []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: api.TerminationMessageReadFile}}, }, } job := &batch.Job{ ObjectMeta: metav1.ObjectMeta{ Name:      "myjob", Namespace: metav1.NamespaceDefault, Annotations: map[string]string{ "foo": "bar", }, ResourceVersion: "0", }, Spec: batch.JobSpec{ Selector:       validSelector, Template:       validPodTemplateSpec, ManualSelector: pointer.BoolPtr(true), Completions:    pointer.Int32Ptr(2), // Set gated values. Suspend:                 pointer.BoolPtr(true), TTLSecondsAfterFinished: pointer.Int32Ptr(0), CompletionMode:          completionModePtr(batch.IndexedCompletion), }, Status: batch.JobStatus{ Active: 11, }, } Strategy.PrepareForCreate(ctx, job) if job.Status.Active != 0 { t.Errorf("Job does not allow setting status on create") } if job.Generation != 1 { t.Errorf("expected Generation=1, got %d", job.Generation) } errs := Strategy.Validate(ctx, job) if len(errs) != 0 { t.Errorf("Unexpected error validating %v", errs) } if job.Spec.CompletionMode == nil { t.Errorf("Job should allow setting .spec.completionMode") } wantAnnotations := map[string]string{ "foo":                        "bar", batchv1.JobTrackingFinalizer: "", } if diff := cmp.Diff(wantAnnotations, job.Annotations); diff != "" { t.Errorf("Job has annotations (-want,+got):n%s", diff) } parallelism := int32(10) // ensure we do not change generation for non-spec updates updatedLabelJob := job.DeepCopy() updatedLabelJob.Labels = map[string]string{"a": "true"} Strategy.PrepareForUpdate(ctx, updatedLabelJob, job) if updatedLabelJob.Generation != 1 { t.Errorf("expected Generation=1, got %d", updatedLabelJob.Generation) } errs = Strategy.ValidateUpdate(ctx, updatedLabelJob, job) if len(errs) != 0 { t.Errorf("Unexpected update validation error") } updatedJob := &batch.Job{ ObjectMeta: metav1.ObjectMeta{ Name:            "bar", ResourceVersion: "4", // remove one annotation and try to enforce the job tracking finalizer. Annotations: map[string]string{batchv1.JobTrackingFinalizer: ""}, }, Spec: batch.JobSpec{ Parallelism: &parallelism, Completions: pointer.Int32Ptr(2), // Update gated features. TTLSecondsAfterFinished: pointer.Int32Ptr(1), CompletionMode:          completionModePtr(batch.IndexedCompletion), // No change because field is immutable. }, Status: batch.JobStatus{ Active: 11, }, } // Ensure we do not change status job.Status.Active = 10 Strategy.PrepareForUpdate(ctx, updatedJob, job) if updatedJob.Status.Active != 10 { t.Errorf("PrepareForUpdate should have preserved prior version status") } if updatedJob.Generation != 2 { t.Errorf("expected Generation=2, got %d", updatedJob.Generation) } wantAnnotations = map[string]string{ batchv1.JobTrackingFinalizer: "", } if diff := cmp.Diff(wantAnnotations, updatedJob.Annotations); diff != "" { t.Errorf("Job has annotations (-want,+got):n%s", diff) } errs = Strategy.ValidateUpdate(ctx, updatedJob, job) if len(errs) == 0 { t.Errorf("Expected a validation error") } // Test updating suspend false->true and nil-> true when the feature gate is // disabled. We don't care about other combinations. job.Spec.Suspend, updatedJob.Spec.Suspend = pointer.BoolPtr(false), pointer.BoolPtr(true) Strategy.PrepareForUpdate(ctx, updatedJob, job) job.Spec.Suspend, updatedJob.Spec.Suspend = nil, pointer.BoolPtr(true) Strategy.PrepareForUpdate(ctx, updatedJob, job) </del> <ins> func TestJobStrategy_GarbageCollectionPolicy(t *testing.T) { </ins> // Make sure we correctly implement the interface. // Otherwise a typo could silently change the default. var gcds rest.GarbageCollectionDeleteStrategy = Strategy