Skip to content

Commit

Permalink
Added rerun pipeline job tests
Browse files Browse the repository at this point in the history
  • Loading branch information
satr committed Oct 12, 2023
1 parent dfc3f09 commit 5c6e904
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 16 deletions.
114 changes: 103 additions & 11 deletions api/jobs/job_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@ package jobs

import (
"context"
"fmt"
"testing"
"time"

secretproviderfake "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned/fake"

deployMock "github.com/equinor/radix-api/api/deployments/mock"
deploymentModels "github.com/equinor/radix-api/api/deployments/models"
jobModels "github.com/equinor/radix-api/api/jobs/models"
"github.com/equinor/radix-api/models"
radixmodels "github.com/equinor/radix-common/models"
models2 "github.com/equinor/radix-common/models"
radixutils "github.com/equinor/radix-common/utils"
v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1"
"github.com/equinor/radix-operator/pkg/apis/radix/v1"
"github.com/equinor/radix-operator/pkg/apis/utils"
"github.com/equinor/radix-operator/pkg/apis/utils/slice"
radixfake "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake"
Expand All @@ -23,6 +22,7 @@ import (
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubefake "k8s.io/client-go/kubernetes/fake"
secretproviderfake "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned/fake"
)

type JobHandlerTestSuite struct {
Expand Down Expand Up @@ -52,16 +52,40 @@ type jobStatusScenario struct {
expectedStatus string
}

type jobProperties struct {
name string
condition v1.RadixJobCondition
stop bool
}

type jobRerunScenario struct {
scenarioName string
existingJob *jobProperties
jobNameToRerun string
expectedError error
}

func TestRunJobHandlerTestSuite(t *testing.T) {
suite.Run(t, new(JobHandlerTestSuite))
}

func (s *JobHandlerTestSuite) SetupTest() {
s.setupTest()
}

func (s *JobHandlerTestSuite) setupTest() {
s.inKubeClient, s.inRadixClient, s.outKubeClient, s.outRadixClient, s.inSecretProviderClient, s.outSecretProviderClient = s.getUtils()
accounts := models.NewAccounts(s.inKubeClient, s.inRadixClient, s.inSecretProviderClient, nil, s.outKubeClient, s.outRadixClient, s.outSecretProviderClient, nil, "", radixmodels.Impersonation{})
accounts := models.NewAccounts(s.inKubeClient, s.inRadixClient, s.inSecretProviderClient, nil, s.outKubeClient, s.outRadixClient, s.outSecretProviderClient, nil, "", models2.Impersonation{})
s.accounts = accounts
}

func (s *JobHandlerTestSuite) getUtils() (inKubeClient *kubefake.Clientset, inRadixClient *radixfake.Clientset, outKubeClient *kubefake.Clientset, outRadixClient *radixfake.Clientset, inSecretProviderClient *secretproviderfake.Clientset, outSecretProviderClient *secretproviderfake.Clientset) {
inKubeClient, outKubeClient = kubefake.NewSimpleClientset(), kubefake.NewSimpleClientset()
inRadixClient, outRadixClient = radixfake.NewSimpleClientset(), radixfake.NewSimpleClientset()
inSecretProviderClient, outSecretProviderClient = secretproviderfake.NewSimpleClientset(), secretproviderfake.NewSimpleClientset()
return
}

func (s *JobHandlerTestSuite) Test_GetApplicationJob() {
jobName, appName, branch, commitId, pipeline, triggeredBy := "a_job", "an_app", "a_branch", "a_commitid", v1.BuildDeploy, "a_user"
started, ended := metav1.NewTime(time.Date(2020, 1, 1, 0, 0, 0, 0, time.Local)), metav1.NewTime(time.Date(2020, 1, 2, 0, 0, 0, 0, time.Local))
Expand Down Expand Up @@ -90,7 +114,8 @@ func (s *JobHandlerTestSuite) Test_GetApplicationJob() {
},
},
}
s.outRadixClient.RadixV1().RadixJobs(rj.Namespace).Create(context.Background(), rj, metav1.CreateOptions{})
_, err := s.outRadixClient.RadixV1().RadixJobs(rj.Namespace).Create(context.Background(), rj, metav1.CreateOptions{})
s.NoError(err)

deploymentName := "a_deployment"
comp1Name, comp1Type, comp1Image := "comp1", "type1", "image1"
Expand Down Expand Up @@ -229,9 +254,76 @@ func (s *JobHandlerTestSuite) Test_GetApplicationJob_Status() {
}
}

func (s *JobHandlerTestSuite) getUtils() (inKubeClient *kubefake.Clientset, inRadixClient *radixfake.Clientset, outKubeClient *kubefake.Clientset, outRadixClient *radixfake.Clientset, inSecretProviderClient *secretproviderfake.Clientset, outSecretProviderClient *secretproviderfake.Clientset) {
inKubeClient, outKubeClient = kubefake.NewSimpleClientset(), kubefake.NewSimpleClientset()
inRadixClient, outRadixClient = radixfake.NewSimpleClientset(), radixfake.NewSimpleClientset()
inSecretProviderClient, outSecretProviderClient = secretproviderfake.NewSimpleClientset(), secretproviderfake.NewSimpleClientset()
return
func (s *JobHandlerTestSuite) TestJobHandler_RerunJob() {
appName := "anyApp"
namespace := utils.GetAppNamespace(appName)
tests := []jobRerunScenario{
{scenarioName: "existing failed job", existingJob: &jobProperties{name: "job1", condition: v1.JobFailed}, jobNameToRerun: "job1", expectedError: nil},
{scenarioName: "existing stopped job", existingJob: &jobProperties{name: "job1", condition: v1.JobStopped, stop: true}, jobNameToRerun: "job1", expectedError: nil},
{scenarioName: "existing running job", existingJob: &jobProperties{name: "job1", condition: v1.JobRunning}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobRunning)},
{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: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobQueued)},
{scenarioName: "existing succeeded job", existingJob: &jobProperties{name: "job1", condition: v1.JobSucceeded}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobSucceeded)},
{scenarioName: "existing waiting job", existingJob: &jobProperties{name: "job1", condition: v1.JobWaiting}, jobNameToRerun: "job1", expectedError: jobModels.JobHasInvalidConditionToRerunError(appName, "job1", v1.JobWaiting)},
{scenarioName: "not existing job", existingJob: nil, jobNameToRerun: "job1", expectedError: jobModels.PipelineNotFoundError(appName, "job1")},
}
for _, tt := range tests {
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,
}
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)
}

err := jh.RerunJob(context.Background(), appName, tt.jobNameToRerun)
s.Equal(tt.expectedError, err)
})
}
}

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.
}
for _, tt := range tests {
s.T().Run(tt.name, func(t *testing.T) {
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,
}

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))
})
}
}
19 changes: 14 additions & 5 deletions api/jobs/manage_job_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import (

jobModels "github.com/equinor/radix-api/api/jobs/models"
"github.com/equinor/radix-api/api/kubequery"
"github.com/equinor/radix-common/utils/slice"
v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1"
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var jobConditionsAllowedForRerun = []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)
Expand All @@ -32,18 +35,21 @@ 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)
srcRadixJob, err := jh.getPipelineJob(ctx, appName, srcJobName)
radixJob, err := jh.getPipelineJob(ctx, appName, srcJobName)
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)
}

destRadixJob := jh.buildPipelineJobRerunFrom(srcRadixJob)
_, err = jh.createPipelineJob(ctx, appName, destRadixJob)
copiedRadixJob := jh.buildPipelineJobRerunFrom(radixJob)
_, err = jh.createPipelineJob(ctx, appName, copiedRadixJob)
if err != nil {
return fmt.Errorf("failed to create a job %s to rerun: %v", srcRadixJob.GetName(), err)
return fmt.Errorf("failed to create a job %s to rerun: %v", radixJob.GetName(), err)
}

log.Infof("reran the job %s as a new job %s in the application %s", srcRadixJob.GetName(), destRadixJob.GetName(), appName)
log.Infof("reran the job %s as a new job %s in the application %s", radixJob.GetName(), copiedRadixJob.GetName(), appName)
return nil
}

Expand All @@ -57,6 +63,9 @@ func (jh JobHandler) buildPipelineJobRerunFrom(srcRadixJob *v1.RadixJob) *v1.Rad
},
Spec: srcRadixJob.Spec,
}
if destRadixJob.ObjectMeta.Annotations == nil {
destRadixJob.ObjectMeta.Annotations = make(map[string]string)
}
destRadixJob.ObjectMeta.Annotations[jobModels.RadixPipelineJobRerunAnnotation] = srcRadixJob.GetName()
if len(destRadixJob.Spec.Build.ImageTag) > 0 {
destRadixJob.Spec.Build.ImageTag = imageTag
Expand Down
6 changes: 6 additions & 0 deletions api/jobs/models/job_errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

radixhttp "github.com/equinor/radix-common/net/http"
v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1"
)

// PipelineNotFoundError Pipeline job not found
Expand All @@ -20,3 +21,8 @@ func PipelineStepNotFoundError(appName, jobName, stepName string) error {
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))
}

0 comments on commit 5c6e904

Please sign in to comment.