From 2ba24e0258f57f9538a6819d093277a0b298a231 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Fri, 13 Oct 2023 15:01:29 +0200 Subject: [PATCH] Added stop pipeline job tests --- api/jobs/job_handler_test.go | 63 ++++++++++++++++++---------------- api/jobs/manage_job_handler.go | 27 ++++++++++----- api/jobs/models/job_errors.go | 15 +++++--- 3 files changed, 62 insertions(+), 43 deletions(-) diff --git a/api/jobs/job_handler_test.go b/api/jobs/job_handler_test.go index a4efdf05..95be213b 100644 --- a/api/jobs/job_handler_test.go +++ b/api/jobs/job_handler_test.go @@ -2,7 +2,6 @@ package jobs import ( "context" - "fmt" "testing" "time" @@ -273,12 +272,7 @@ func (s *JobHandlerTestSuite) TestJobHandler_RerunJob() { ctrl := gomock.NewController(s.T()) defer ctrl.Finish() dh := deployMock.NewMockDeployHandler(ctrl) - jh := JobHandler{ - accounts: s.accounts, - userAccount: s.accounts.UserAccount, - serviceAccount: s.accounts.ServiceAccount, - deploy: dh, - } + jh := s.getJobHandler(dh) if tt.existingJob != nil { _, err := s.inRadixClient.RadixV1().RadixJobs(namespace).Create(context.Background(), &v1.RadixJob{ ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: tt.existingJob.name}, @@ -295,35 +289,46 @@ func (s *JobHandlerTestSuite) TestJobHandler_RerunJob() { } func (s *JobHandlerTestSuite) TestJobHandler_StopJob() { - type args struct { - ctx context.Context - appName string - jobName string - } - // appName := "anyApp" - tests := []struct { - name string - setMocks func(s *JobHandlerTestSuite, deployHandlerMock *deployMock.MockDeployHandler) - args args - wantErr assert.ErrorAssertionFunc - }{ - // TODO: Add test cases. + appName := "anyApp" + namespace := utils.GetAppNamespace(appName) + tests := []jobRerunScenario{ + {scenarioName: "existing failed job", existingJob: &jobProperties{name: "job1", condition: v1.JobFailed}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobFailed)}, + {scenarioName: "existing stopped job", existingJob: &jobProperties{name: "job1", condition: v1.JobStopped, stop: true}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToStopError(appName, "job1", v1.JobStopped)}, + {scenarioName: "existing running job with stop in spec", existingJob: &jobProperties{name: "job1", condition: v1.JobRunning, stop: true}, jobNameToRerun: "job1", expectedError: jobModels.JobAlreadyRequestedToStopError(appName, "job1")}, + {scenarioName: "existing running job", existingJob: &jobProperties{name: "job1", condition: v1.JobRunning}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing stopped-no-changes job", existingJob: &jobProperties{name: "job1", condition: v1.JobStoppedNoChanges}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobStoppedNoChanges)}, + {scenarioName: "existing queued job", existingJob: &jobProperties{name: "job1", condition: v1.JobQueued}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing succeeded job", existingJob: &jobProperties{name: "job1", condition: v1.JobSucceeded}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "existing waiting job", existingJob: &jobProperties{name: "job1", condition: v1.JobWaiting}, jobNameToRerun: "job1", expectedError: nil}, + {scenarioName: "not existing job", existingJob: nil, jobNameToRerun: "job1", expectedError: jobModels.PipelineNotFoundError(appName, "job1")}, } for _, tt := range tests { - s.T().Run(tt.name, func(t *testing.T) { + s.T().Run(tt.scenarioName, func(t *testing.T) { + s.setupTest() ctrl := gomock.NewController(s.T()) defer ctrl.Finish() dh := deployMock.NewMockDeployHandler(ctrl) - jh := JobHandler{ - accounts: s.accounts, - userAccount: s.accounts.UserAccount, - serviceAccount: s.accounts.ServiceAccount, - deploy: dh, + jh := s.getJobHandler(dh) + if tt.existingJob != nil { + _, err := s.inRadixClient.RadixV1().RadixJobs(namespace).Create(context.Background(), &v1.RadixJob{ + ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: tt.existingJob.name}, + Spec: v1.RadixJobSpec{Stop: tt.existingJob.stop}, + Status: v1.RadixJobStatus{Condition: tt.existingJob.condition}, + }, metav1.CreateOptions{}) + s.NoError(err) } - tt.setMocks(s, dh) - - tt.wantErr(t, jh.StopJob(tt.args.ctx, tt.args.appName, tt.args.jobName), fmt.Sprintf("StopJob(%v, %v, %v)", tt.args.ctx, tt.args.appName, tt.args.jobName)) + err := jh.StopJob(context.Background(), appName, tt.jobNameToRerun) + s.Equal(tt.expectedError, err) }) } } + +func (s *JobHandlerTestSuite) getJobHandler(dh *deployMock.MockDeployHandler) JobHandler { + return JobHandler{ + accounts: s.accounts, + userAccount: s.accounts.UserAccount, + serviceAccount: s.accounts.ServiceAccount, + deploy: dh, + } +} diff --git a/api/jobs/manage_job_handler.go b/api/jobs/manage_job_handler.go index 7355f3ad..daf01113 100644 --- a/api/jobs/manage_job_handler.go +++ b/api/jobs/manage_job_handler.go @@ -13,19 +13,28 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -var jobConditionsAllowedForRerun = []v1.RadixJobCondition{v1.JobFailed, v1.JobStopped} +var ( + jobConditionsInValidForJobStop = []v1.RadixJobCondition{v1.JobFailed, v1.JobStopped, v1.JobStoppedNoChanges} + jobConditionsValidForJobRerun = []v1.RadixJobCondition{v1.JobFailed, v1.JobStopped} +) // StopJob Stops an application job func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error { log.Infof("Stopping the job: %s, %s", jobName, appName) - job, err := jh.getPipelineJob(ctx, appName, jobName) + radixJob, err := jh.getPipelineJob(ctx, appName, jobName) if err != nil { return err } + if radixJob.Spec.Stop { + return jobModels.JobAlreadyRequestedToStopError(appName, jobName) + } + if slice.Any(jobConditionsInValidForJobStop, func(condition v1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { + return jobModels.JobHasInvalidConditionToStopError(appName, jobName, radixJob.Status.Condition) + } - job.Spec.Stop = true + radixJob.Spec.Stop = true - _, err = jh.userAccount.RadixClient.RadixV1().RadixJobs(job.GetNamespace()).Update(ctx, job, metav1.UpdateOptions{}) + _, err = jh.userAccount.RadixClient.RadixV1().RadixJobs(radixJob.GetNamespace()).Update(ctx, radixJob, metav1.UpdateOptions{}) if err != nil { return fmt.Errorf("failed to patch job object: %v", err) } @@ -33,14 +42,14 @@ func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error } // RerunJob Reruns the pipeline job as a copy -func (jh JobHandler) RerunJob(ctx context.Context, appName, srcJobName string) error { - log.Infof("Rerunning the job %s in the application %s", srcJobName, appName) - radixJob, err := jh.getPipelineJob(ctx, appName, srcJobName) +func (jh JobHandler) RerunJob(ctx context.Context, appName, jobName string) error { + log.Infof("Rerunning the job %s in the application %s", jobName, appName) + radixJob, err := jh.getPipelineJob(ctx, appName, jobName) if err != nil { return err } - if !slice.Any(jobConditionsAllowedForRerun, func(condition v1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { - return jobModels.JobHasInvalidConditionToRerunError(appName, srcJobName, radixJob.Status.Condition) + if !slice.Any(jobConditionsValidForJobRerun, func(condition v1.RadixJobCondition) bool { return condition == radixJob.Status.Condition }) { + return jobModels.JobHasInvalidConditionToRerunError(appName, jobName, radixJob.Status.Condition) } copiedRadixJob := jh.buildPipelineJobRerunFrom(radixJob) diff --git a/api/jobs/models/job_errors.go b/api/jobs/models/job_errors.go index 7abb1a71..7c00c972 100644 --- a/api/jobs/models/job_errors.go +++ b/api/jobs/models/job_errors.go @@ -17,12 +17,17 @@ func PipelineStepNotFoundError(appName, jobName, stepName string) error { return radixhttp.TypeMissingError(fmt.Sprintf("step %s for the job %s not found for the app %s", stepName, jobName, appName), nil) } -// PipelineRunNotFoundError Tekton PipelineRun not found for the pipeline job -func PipelineRunNotFoundError(appName, jobName, pipelineRunName string) error { - return radixhttp.TypeMissingError(fmt.Sprintf("pipeline run %s not found for the app %s and the pipeline job %s", pipelineRunName, appName, jobName), nil) -} - // JobHasInvalidConditionToRerunError Pipeline job cannot be rerun due to invalid condition func JobHasInvalidConditionToRerunError(appName, jobName string, jobCondition v1.RadixJobCondition) error { return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only Failed or Stopped pipeline jobs can be rerun, the job %s for the app %s has status %s", appName, jobName, jobCondition)) } + +// JobAlreadyRequestedToStopError Pipeline job was already requested to stop +func JobAlreadyRequestedToStopError(appName, jobName string) error { + return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("job %s for the app %s is already requested to stop", appName, jobName)) +} + +// JobHasInvalidConditionToStopError Pipeline job cannot be stopped due to invalid condition +func JobHasInvalidConditionToStopError(appName, jobName string, jobCondition v1.RadixJobCondition) error { + return radixhttp.ValidationError("Radix Application Pipeline", fmt.Sprintf("only not Failed or Stopped pipeline jobs can be stopped, the job %s for the app %s has status %s", appName, jobName, jobCondition)) +}