diff --git a/pkg/controllers/job/job_state_test.go b/pkg/controllers/job/job_state_test.go new file mode 100644 index 0000000000..a45c5432e0 --- /dev/null +++ b/pkg/controllers/job/job_state_test.go @@ -0,0 +1,1568 @@ +/* +Copyright 2019 The Volcano Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package job + +import ( + "fmt" + "k8s.io/api/core/v1" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "volcano.sh/volcano/pkg/apis/batch/v1alpha1" + "volcano.sh/volcano/pkg/controllers/apis" + "volcano.sh/volcano/pkg/controllers/job/state" +) + +func TestAbortedState_Execute(t *testing.T) { + namespace := "test" + + testcases := []struct { + Name string + JobInfo *apis.JobInfo + Action v1alpha1.Action + ExpectedVal error + }{ + { + Name: "AbortedState-ResumeAction case", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Aborted, + }, + }, + }, + }, + Action: v1alpha1.ResumeJobAction, + ExpectedVal: nil, + }, + { + Name: "AbortedState-AnyOtherAction case", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Aborted, + }, + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + } + + for _, testcase := range testcases { + absState := state.NewState(testcase.JobInfo) + + fakecontroller := newFakeController() + state.KillJob = fakecontroller.killJob + + _, err := fakecontroller.vkClients.BatchV1alpha1().Jobs(namespace).Create(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while creating Job") + } + + err = fakecontroller.cache.Add(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while adding Job in cache") + } + + err = absState.Execute(testcase.Action) + if err != nil { + t.Errorf("Expected Error not to occur but got: %s", err) + } + if testcase.Action == v1alpha1.ResumeJobAction { + jobInfo, err := fakecontroller.cache.Get(fmt.Sprintf("%s/%s", testcase.JobInfo.Job.Namespace, testcase.JobInfo.Job.Name)) + if err != nil { + t.Error("Error while retrieving value from Cache") + } + + if jobInfo.Job.Status.State.Phase != v1alpha1.Restarting { + t.Error("Expected Phase to be equal to restarting phase") + } + } + } +} + +func TestAbortingState_Execute(t *testing.T) { + namespace := "test" + + testcases := []struct { + Name string + JobInfo *apis.JobInfo + Action v1alpha1.Action + ExpectedVal error + }{ + { + Name: "AbortedState-ResumeAction case", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Aborting, + }, + }, + }, + }, + Action: v1alpha1.ResumeJobAction, + ExpectedVal: nil, + }, + { + Name: "AbortedState-AnyOtherAction case with pods count equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Aborting, + }, + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + { + Name: "AbortedState-AnyOtherAction case with Pods count not equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + Pending: 1, + State: v1alpha1.JobState{ + Phase: v1alpha1.Aborting, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodPending, nil), + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + } + + for _, testcase := range testcases { + absState := state.NewState(testcase.JobInfo) + + fakecontroller := newFakeController() + state.KillJob = fakecontroller.killJob + + _, err := fakecontroller.vkClients.BatchV1alpha1().Jobs(namespace).Create(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while creating Job") + } + + err = fakecontroller.cache.Add(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while adding Job in cache") + } + + err = absState.Execute(testcase.Action) + if err != nil { + t.Errorf("Expected Error not to occur but got: %s", err) + } + if testcase.Action == v1alpha1.ResumeJobAction { + jobInfo, err := fakecontroller.cache.Get(fmt.Sprintf("%s/%s", testcase.JobInfo.Job.Namespace, testcase.JobInfo.Job.Name)) + if err != nil { + t.Error("Error while retrieving value from Cache") + } + + if jobInfo.Job.Status.RetryCount == 0 { + t.Error("Retry Count should not be zero") + } + } + + if testcase.Action != v1alpha1.ResumeJobAction { + jobInfo, err := fakecontroller.cache.Get(fmt.Sprintf("%s/%s", testcase.JobInfo.Job.Namespace, testcase.JobInfo.Job.Name)) + if err != nil { + t.Error("Error while retrieving value from Cache") + } + + if testcase.JobInfo.Job.Status.Pending == 0 && testcase.JobInfo.Job.Status.Running == 0 && testcase.JobInfo.Job.Status.Terminating == 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Aborted { + t.Error("Phase Should be aborted") + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Aborting { + t.Error("Phase Should be aborted") + } + } + } + } +} + +func TestCompletingState_Execute(t *testing.T) { + + namespace := "test" + + testcases := []struct { + Name string + JobInfo *apis.JobInfo + Action v1alpha1.Action + ExpectedVal error + }{ + { + Name: "CompletingState- With pod count not equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + Running: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Completing, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.ResumeJobAction, + ExpectedVal: nil, + }, + { + Name: "CompletingState- With pod count equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Completing, + }, + }, + }, + }, + Action: v1alpha1.ResumeJobAction, + ExpectedVal: nil, + }, + } + + for i, testcase := range testcases { + testState := state.NewState(testcase.JobInfo) + + fakecontroller := newFakeController() + state.KillJob = fakecontroller.killJob + + _, err := fakecontroller.vkClients.BatchV1alpha1().Jobs(namespace).Create(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while creating Job") + } + + err = fakecontroller.cache.Add(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while adding Job in cache") + } + + err = testState.Execute(testcase.Action) + if err != nil { + t.Errorf("Expected Error not to occur but got: %s", err) + } + + jobInfo, err := fakecontroller.cache.Get(fmt.Sprintf("%s/%s", testcase.JobInfo.Job.Namespace, testcase.JobInfo.Job.Name)) + if err != nil { + t.Error("Error while retrieving value from Cache") + } + + if testcase.JobInfo.Job.Status.Running == 0 && testcase.JobInfo.Job.Status.Pending == 0 && testcase.JobInfo.Job.Status.Terminating == 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Completed { + fmt.Println(jobInfo.Job.Status.State.Phase) + t.Errorf("Expected Phase to be Completed State in test case: %d", i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Completing { + t.Errorf("Expected Phase to be completing state in test case: %d", i) + } + } + } +} + +func TestFinishedState_Execute(t *testing.T) { + namespace := "test" + + testcases := []struct { + Name string + JobInfo *apis.JobInfo + Action v1alpha1.Action + ExpectedVal error + }{ + { + Name: "FinishedState Test Case", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Completed, + }, + }, + }, + }, + Action: v1alpha1.ResumeJobAction, + ExpectedVal: nil, + }, + } + + for _, testcase := range testcases { + testState := state.NewState(testcase.JobInfo) + + fakecontroller := newFakeController() + state.KillJob = fakecontroller.killJob + + _, err := fakecontroller.vkClients.BatchV1alpha1().Jobs(namespace).Create(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while creating Job") + } + + err = fakecontroller.cache.Add(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while adding Job in cache") + } + + err = testState.Execute(testcase.Action) + if err != nil { + t.Errorf("Expected Error not to occur but got: %s", err) + } + } +} + +func TestInqueueState_Execute(t *testing.T) { + namespace := "test" + + testcases := []struct { + Name string + JobInfo *apis.JobInfo + Action v1alpha1.Action + ExpectedVal error + }{ + { + Name: "InqueueState- RestartJobAction case With terminating pod count equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Inqueue, + }, + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + { + Name: "InqueueState- RestartJobAction case With terminating pod count not equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Inqueue, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + { + Name: "InqueueState- AbortJobAction case With terminating pod count equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Inqueue, + }, + }, + }, + }, + Action: v1alpha1.AbortJobAction, + ExpectedVal: nil, + }, + { + Name: "InqueueState- AbortJobAction case With terminating pod count not equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Inqueue, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.AbortJobAction, + ExpectedVal: nil, + }, + { + Name: "InqueueState- CompleteJobAction case With terminating pod count equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Inqueue, + }, + }, + }, + }, + Action: v1alpha1.CompleteJobAction, + ExpectedVal: nil, + }, + { + Name: "InqueueState- CompleteJobAction case With terminating pod count not equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Inqueue, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.CompleteJobAction, + ExpectedVal: nil, + }, + { + Name: "InqueueState- Default case With Min Available equal to running pods", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{ + MinAvailable: 3, + }, + Status: v1alpha1.JobStatus{ + Running: 3, + State: v1alpha1.JobState{ + Phase: v1alpha1.Inqueue, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + "pod3": buildPod(namespace, "pod3", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.ResumeJobAction, + ExpectedVal: nil, + }, + { + Name: "InqueueState- Default case With Min Available not equal to running pods", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{ + MinAvailable: 3, + }, + Status: v1alpha1.JobStatus{ + Running: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Inqueue, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.ResumeJobAction, + ExpectedVal: nil, + }, + } + + for i, testcase := range testcases { + testState := state.NewState(testcase.JobInfo) + + fakecontroller := newFakeController() + state.KillJob = fakecontroller.killJob + + _, err := fakecontroller.vkClients.BatchV1alpha1().Jobs(namespace).Create(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while creating Job") + } + + err = fakecontroller.cache.Add(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while adding Job in cache") + } + + err = testState.Execute(testcase.Action) + if err != nil { + t.Errorf("Expected Error not to occur but got: %s", err) + } + + jobInfo, err := fakecontroller.cache.Get(fmt.Sprintf("%s/%s", testcase.JobInfo.Job.Namespace, testcase.JobInfo.Job.Name)) + if err != nil { + t.Error("Error while retrieving value from Cache") + } + + if testcase.Action == v1alpha1.RestartJobAction { + if jobInfo.Job.Status.Terminating == 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Pending { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Pending, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Restarting { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Restarting, jobInfo.Job.Status.State.Phase, i) + } + } + } else if testcase.Action == v1alpha1.AbortJobAction { + if jobInfo.Job.Status.Terminating == 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Pending { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Pending, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Aborting { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Restarting, jobInfo.Job.Status.State.Phase, i) + } + } + } else if testcase.Action == v1alpha1.CompleteJobAction { + if jobInfo.Job.Status.Terminating == 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Completed { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Completed, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Completing { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Restarting, jobInfo.Job.Status.State.Phase, i) + } + } + } else { + if jobInfo.Job.Spec.MinAvailable <= jobInfo.Job.Status.Running+jobInfo.Job.Status.Succeeded+jobInfo.Job.Status.Failed { + if jobInfo.Job.Status.State.Phase != v1alpha1.Running { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Running, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != testcase.JobInfo.Job.Status.State.Phase { + t.Errorf("Expected Job phase to %s, but got %s in case %d", testcase.JobInfo.Job.Status.State.Phase, jobInfo.Job.Status.State.Phase, i) + } + } + } + } +} + +func TestPendingState_Execute(t *testing.T) { + namespace := "test" + + testcases := []struct { + Name string + JobInfo *apis.JobInfo + Action v1alpha1.Action + ExpectedVal error + }{ + { + Name: "PendingState- RestartJobAction case With terminating pod count equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Pending, + }, + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + { + Name: "PendingState- RestartJobAction case With terminating pod count not equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Pending, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + { + Name: "PendingState- AbortJobAction case With terminating pod count equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Pending, + }, + }, + }, + }, + Action: v1alpha1.AbortJobAction, + ExpectedVal: nil, + }, + { + Name: "PendingState- AbortJobAction case With terminating pod count not equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Pending, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.AbortJobAction, + ExpectedVal: nil, + }, + { + Name: "PendingState- CompleteJobAction case With terminating pod count equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Pending, + }, + }, + }, + }, + Action: v1alpha1.CompleteJobAction, + ExpectedVal: nil, + }, + { + Name: "PendingState- CompleteJobAction case With terminating pod count not equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Pending, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.CompleteJobAction, + ExpectedVal: nil, + }, + { + Name: "PendingState- EnqueueAction case With Min Available equal to running pods", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{ + MinAvailable: 3, + }, + Status: v1alpha1.JobStatus{ + Running: 3, + State: v1alpha1.JobState{ + Phase: v1alpha1.Pending, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + "pod3": buildPod(namespace, "pod3", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.EnqueueAction, + ExpectedVal: nil, + }, + { + Name: "PendingState- EnqueueAction case With Min Available not equal to running pods", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{ + MinAvailable: 3, + }, + Status: v1alpha1.JobStatus{ + Running: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Pending, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.EnqueueAction, + ExpectedVal: nil, + }, + { + Name: "PendingState- Default case With Min Available equal to running pods", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{ + MinAvailable: 3, + }, + Status: v1alpha1.JobStatus{ + Running: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Pending, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.SyncJobAction, + ExpectedVal: nil, + }, + } + + for i, testcase := range testcases { + testState := state.NewState(testcase.JobInfo) + + fakecontroller := newFakeController() + state.KillJob = fakecontroller.killJob + + _, err := fakecontroller.vkClients.BatchV1alpha1().Jobs(namespace).Create(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while creating Job") + } + + err = fakecontroller.cache.Add(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while adding Job in cache") + } + + err = testState.Execute(testcase.Action) + if err != nil { + t.Errorf("Expected Error not to occur but got: %s", err) + } + + jobInfo, err := fakecontroller.cache.Get(fmt.Sprintf("%s/%s", testcase.JobInfo.Job.Namespace, testcase.JobInfo.Job.Name)) + if err != nil { + t.Error("Error while retrieving value from Cache") + } + + if testcase.Action == v1alpha1.RestartJobAction { + if jobInfo.Job.Status.Terminating == 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Pending { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Pending, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Restarting { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Restarting, jobInfo.Job.Status.State.Phase, i) + } + } + } else if testcase.Action == v1alpha1.AbortJobAction { + if jobInfo.Job.Status.Terminating == 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Pending { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Pending, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Aborting { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Restarting, jobInfo.Job.Status.State.Phase, i) + } + } + } else if testcase.Action == v1alpha1.CompleteJobAction { + if jobInfo.Job.Status.Terminating == 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Completed { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Completed, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Completing { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Restarting, jobInfo.Job.Status.State.Phase, i) + } + } + } else if testcase.Action == v1alpha1.EnqueueAction { + if jobInfo.Job.Spec.MinAvailable <= jobInfo.Job.Status.Running+jobInfo.Job.Status.Succeeded+jobInfo.Job.Status.Failed { + if jobInfo.Job.Status.State.Phase != v1alpha1.Running { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Running, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Inqueue { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Inqueue, jobInfo.Job.Status.State.Phase, i) + } + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Pending { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Pending, jobInfo.Job.Status.State.Phase, i) + } + } + } +} + +func TestRestartingState_Execute(t *testing.T) { + namespace := "test" + + testcases := []struct { + Name string + JobInfo *apis.JobInfo + Action v1alpha1.Action + ExpectedVal error + }{ + { + Name: "RestartingState- RetryCount is equal to or greater than MaxRetry", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{ + MaxRetry: 3, + }, + Status: v1alpha1.JobStatus{ + RetryCount: 3, + State: v1alpha1.JobState{ + Phase: v1alpha1.Restarting, + }, + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + { + Name: "RestartingState- RetryCount is less than MaxRetry", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{ + MaxRetry: 3, + Tasks: []v1alpha1.TaskSpec{ + { + Name: "task1", + }, + { + Name: "task2", + }, + }, + }, + Status: v1alpha1.JobStatus{ + RetryCount: 1, + MinAvailable: 1, + Terminating: 0, + State: v1alpha1.JobState{ + Phase: v1alpha1.Restarting, + }, + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + } + + for i, testcase := range testcases { + testState := state.NewState(testcase.JobInfo) + + fakecontroller := newFakeController() + state.KillJob = fakecontroller.killJob + + _, err := fakecontroller.vkClients.BatchV1alpha1().Jobs(namespace).Create(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while creating Job") + } + + err = fakecontroller.cache.Add(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while adding Job in cache") + } + + err = testState.Execute(testcase.Action) + if err != nil { + t.Errorf("Expected Error not to occur but got: %s", err) + } + + jobInfo, err := fakecontroller.cache.Get(fmt.Sprintf("%s/%s", testcase.JobInfo.Job.Namespace, testcase.JobInfo.Job.Name)) + if err != nil { + t.Error("Error while retrieving value from Cache") + } + + if testcase.JobInfo.Job.Spec.MaxRetry <= testcase.JobInfo.Job.Status.RetryCount { + if jobInfo.Job.Status.State.Phase != v1alpha1.Failed { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Failed, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Pending { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Pending, jobInfo.Job.Status.State.Phase, i) + } + } + } +} + +func TestRunningState_Execute(t *testing.T) { + namespace := "test" + + testcases := []struct { + Name string + JobInfo *apis.JobInfo + Action v1alpha1.Action + ExpectedVal error + }{ + { + Name: "RunningState- RestartJobAction case and Terminating Pods not equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{}, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + { + Name: "RunningState- RestartJobAction case and Terminating Pods equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{}, + Status: v1alpha1.JobStatus{ + Terminating: 0, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + }, + Action: v1alpha1.RestartJobAction, + ExpectedVal: nil, + }, + { + Name: "RunningState- AbortAction case and Terminating Pods equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{}, + Status: v1alpha1.JobStatus{ + Terminating: 0, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + }, + Action: v1alpha1.AbortJobAction, + ExpectedVal: nil, + }, + { + Name: "RunningState- AbortAction case and Terminating Pods not equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{}, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.AbortJobAction, + ExpectedVal: nil, + }, + { + Name: "RunningState- TerminateJobAction case and Terminating Pods equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{}, + Status: v1alpha1.JobStatus{ + Terminating: 0, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + }, + Action: v1alpha1.TerminateJobAction, + ExpectedVal: nil, + }, + { + Name: "RunningState- TerminateJobAction case and Terminating Pods not equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{}, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.TerminateJobAction, + ExpectedVal: nil, + }, + { + Name: "RunningState- CompleteJobAction case and Terminating Pods equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{}, + Status: v1alpha1.JobStatus{ + Terminating: 0, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + }, + Action: v1alpha1.CompleteJobAction, + ExpectedVal: nil, + }, + { + Name: "RunningState- CompleteJobAction case and Terminating Pods not equal to 0", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{}, + Status: v1alpha1.JobStatus{ + Terminating: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.CompleteJobAction, + ExpectedVal: nil, + }, + { + Name: "RunningState- Default case and Total is equal to failed+succeeded", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{ + Tasks: []v1alpha1.TaskSpec{ + { + Name: "task1", + Replicas: 2, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: "task1", + }, + }, + }, + }, + }, + Status: v1alpha1.JobStatus{ + Succeeded: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "job1-task1-0": buildPod(namespace, "pod1", v1.PodSucceeded, nil), + "job1-task1-1": buildPod(namespace, "pod2", v1.PodSucceeded, nil), + }, + }, + }, + Action: v1alpha1.SyncJobAction, + ExpectedVal: nil, + }, + { + Name: "RunningState- Default case and Total is not equal to failed+succeeded", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "job1", + Namespace: namespace, + }, + Spec: v1alpha1.JobSpec{ + Tasks: []v1alpha1.TaskSpec{ + { + Name: "task1", + Replicas: 2, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: "task1", + }, + }, + }, + }, + }, + Status: v1alpha1.JobStatus{ + Succeeded: 1, + State: v1alpha1.JobState{ + Phase: v1alpha1.Running, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "job1-task1-0": buildPod(namespace, "pod1", v1.PodSucceeded, nil), + }, + }, + }, + Action: v1alpha1.SyncJobAction, + ExpectedVal: nil, + }, + } + + for i, testcase := range testcases { + testState := state.NewState(testcase.JobInfo) + + fakecontroller := newFakeController() + state.KillJob = fakecontroller.killJob + + _, err := fakecontroller.vkClients.BatchV1alpha1().Jobs(namespace).Create(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while creating Job") + } + + err = fakecontroller.cache.Add(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while adding Job in cache") + } + + err = testState.Execute(testcase.Action) + if err != nil { + t.Errorf("Expected Error not to occur but got: %s", err) + } + + jobInfo, err := fakecontroller.cache.Get(fmt.Sprintf("%s/%s", testcase.JobInfo.Job.Namespace, testcase.JobInfo.Job.Name)) + if err != nil { + t.Error("Error while retrieving value from Cache") + } + + if testcase.Action == v1alpha1.RestartJobAction { + if testcase.JobInfo.Job.Status.Terminating != 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Restarting { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Restarting, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Running { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Running, jobInfo.Job.Status.State.Phase, i) + } + } + } else if testcase.Action == v1alpha1.AbortJobAction { + if testcase.JobInfo.Job.Status.Terminating != 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Aborting { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Aborting, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Running { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Running, jobInfo.Job.Status.State.Phase, i) + } + } + } else if testcase.Action == v1alpha1.TerminateJobAction { + if testcase.JobInfo.Job.Status.Terminating != 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Terminating { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Terminating, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Running { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Running, jobInfo.Job.Status.State.Phase, i) + } + } + } else if testcase.Action == v1alpha1.CompleteJobAction { + if testcase.JobInfo.Job.Status.Terminating != 0 { + if jobInfo.Job.Status.State.Phase != v1alpha1.Completing { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Completing, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Completed { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Completed, jobInfo.Job.Status.State.Phase, i) + } + } + } else { + total := state.TotalTasks(testcase.JobInfo.Job) + if total == testcase.JobInfo.Job.Status.Succeeded+testcase.JobInfo.Job.Status.Failed { + if jobInfo.Job.Status.State.Phase != v1alpha1.Completed { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Completed, jobInfo.Job.Status.State.Phase, i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Running { + t.Errorf("Expected Job phase to %s, but got %s in case %d", v1alpha1.Running, jobInfo.Job.Status.State.Phase, i) + } + } + } + } +} + +func TestTerminatingState_Execute(t *testing.T) { + namespace := "test" + + testcases := []struct { + Name string + JobInfo *apis.JobInfo + Action v1alpha1.Action + ExpectedVal error + }{ + { + Name: "TerminatingState- With pod count not equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + Running: 2, + State: v1alpha1.JobState{ + Phase: v1alpha1.Terminating, + }, + }, + }, + Pods: map[string]map[string]*v1.Pod{ + "task1": { + "pod1": buildPod(namespace, "pod1", v1.PodRunning, nil), + "pod2": buildPod(namespace, "pod2", v1.PodRunning, nil), + }, + }, + }, + Action: v1alpha1.TerminateJobAction, + ExpectedVal: nil, + }, + { + Name: "TerminatingState- With pod count not equal to zero", + JobInfo: &apis.JobInfo{ + Namespace: namespace, + Name: "jobinfo1", + Job: &v1alpha1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "Job1", + Namespace: namespace, + }, + Status: v1alpha1.JobStatus{ + State: v1alpha1.JobState{ + Phase: v1alpha1.Terminating, + }, + }, + }, + }, + Action: v1alpha1.TerminateJobAction, + ExpectedVal: nil, + }, + } + + for i, testcase := range testcases { + testState := state.NewState(testcase.JobInfo) + + fakecontroller := newFakeController() + state.KillJob = fakecontroller.killJob + + _, err := fakecontroller.vkClients.BatchV1alpha1().Jobs(namespace).Create(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while creating Job") + } + + err = fakecontroller.cache.Add(testcase.JobInfo.Job) + if err != nil { + t.Error("Error while adding Job in cache") + } + + err = testState.Execute(testcase.Action) + if err != nil { + t.Errorf("Expected Error not to occur but got: %s", err) + } + + jobInfo, err := fakecontroller.cache.Get(fmt.Sprintf("%s/%s", testcase.JobInfo.Job.Namespace, testcase.JobInfo.Job.Name)) + if err != nil { + t.Error("Error while retrieving value from Cache") + } + + if testcase.JobInfo.Job.Status.Running == 0 && testcase.JobInfo.Job.Status.Pending == 0 && testcase.JobInfo.Job.Status.Terminating == 0 { + + if jobInfo.Job.Status.State.Phase != v1alpha1.Terminated { + fmt.Println(jobInfo.Job.Status.State.Phase) + t.Errorf("Expected Phase to be Terminated State in test case: %d", i) + } + } else { + if jobInfo.Job.Status.State.Phase != v1alpha1.Terminating { + t.Errorf("Expected Phase to be Terminating state in test case: %d", i) + } + } + } +}