diff --git a/api/v1beta2/integrationtestscenario_types.go b/api/v1beta2/integrationtestscenario_types.go index 1c10791d9..3ec505a53 100644 --- a/api/v1beta2/integrationtestscenario_types.go +++ b/api/v1beta2/integrationtestscenario_types.go @@ -20,6 +20,20 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +const ( + // TestLabelPrefix contains the prefix applied to labels and annotations related to testing. + TestLabelPrefix = "test.appstudio.openshift.io" + + // PipelineTimeoutAnnotation contains the name of the application + PipelineTimeoutAnnotation = TestLabelPrefix + "/pipeline_timeout" + + // TasksTimeoutAnnotation contains the name of the application + TasksTimeoutAnnotation = TestLabelPrefix + "/tasks_timeout" + + // FinallyTimeoutAnnotation contains the name of the application + FinallyTimeoutAnnotation = TestLabelPrefix + "/finally_timeout" +) + // IntegrationTestScenarioSpec defines the desired state of IntegrationScenario type IntegrationTestScenarioSpec struct { // Application that's associated with the IntegrationTestScenario diff --git a/internal/controller/snapshot/snapshot_adapter.go b/internal/controller/snapshot/snapshot_adapter.go index 28541af58..449fe9ca4 100644 --- a/internal/controller/snapshot/snapshot_adapter.go +++ b/internal/controller/snapshot/snapshot_adapter.go @@ -788,7 +788,7 @@ func (a *Adapter) createIntegrationPipelineRun(application *applicationapiv1alph WithApplication(a.application). WithExtraParams(integrationTestScenario.Spec.Params). WithFinalizer(h.IntegrationPipelineRunFinalizer). - WithDefaultIntegrationTimeouts(a.logger.Logger) + WithIntegrationTimeouts(integrationTestScenario, a.logger.Logger) if shouldUpdateIntegrationTestGitResolver(integrationTestScenario, snapshot) { pipelineRunBuilder.WithUpdatedTestsGitResolver(getGitResolverUpdateMap(snapshot)) diff --git a/tekton/integration_pipeline.go b/tekton/integration_pipeline.go index c7a7b8b5c..781188ecd 100644 --- a/tekton/integration_pipeline.go +++ b/tekton/integration_pipeline.go @@ -19,6 +19,7 @@ package tekton import ( "encoding/json" "fmt" + integrationv1beta2 "github.com/konflux-ci/integration-service/api/v1beta2" "strings" "os" @@ -264,19 +265,29 @@ func (r *IntegrationPipelineRun) WithApplication(application *applicationapiv1al return r } -// WithDefaultIntegrationTimeouts fetches the default Integration timeouts from the environment variables and adds them -// to the integration PipelineRun. -func (r *IntegrationPipelineRun) WithDefaultIntegrationTimeouts(logger logr.Logger) *IntegrationPipelineRun { +// WithIntegrationTimeouts fetches the Integration timeouts from either the integrationTestScenario annotations or +// the environment variables and adds them to the integration PipelineRun. +func (r *IntegrationPipelineRun) WithIntegrationTimeouts(integrationTestScenario *v1beta2.IntegrationTestScenario, logger logr.Logger) *IntegrationPipelineRun { pipelineTimeoutStr := os.Getenv("PIPELINE_TIMEOUT") + if metadata.HasAnnotation(integrationTestScenario, integrationv1beta2.PipelineTimeoutAnnotation) { + pipelineTimeoutStr = integrationTestScenario.Annotations[integrationv1beta2.PipelineTimeoutAnnotation] + } taskTimeoutStr := os.Getenv("TASKS_TIMEOUT") + if metadata.HasAnnotation(integrationTestScenario, integrationv1beta2.TasksTimeoutAnnotation) { + taskTimeoutStr = integrationTestScenario.Annotations[integrationv1beta2.TasksTimeoutAnnotation] + } finallyTimeoutStr := os.Getenv("FINALLY_TIMEOUT") + if metadata.HasAnnotation(integrationTestScenario, integrationv1beta2.FinallyTimeoutAnnotation) { + finallyTimeoutStr = integrationTestScenario.Annotations[integrationv1beta2.FinallyTimeoutAnnotation] + } + r.Spec.Timeouts = &tektonv1.TimeoutFields{} if pipelineTimeoutStr != "" { pipelineRunTimeout, err := time.ParseDuration(pipelineTimeoutStr) if err == nil { r.Spec.Timeouts.Pipeline = &metav1.Duration{Duration: pipelineRunTimeout} } else { - logger.Error(err, "failed to parse default PIPELINE_TIMEOUT") + logger.Error(err, "failed to parse the PIPELINE_TIMEOUT") } } if taskTimeoutStr != "" { @@ -284,7 +295,7 @@ func (r *IntegrationPipelineRun) WithDefaultIntegrationTimeouts(logger logr.Logg if err == nil { r.Spec.Timeouts.Tasks = &metav1.Duration{Duration: taskTimeout} } else { - logger.Error(err, "failed to parse default TASKS_TIMEOUT") + logger.Error(err, "failed to parse the TASKS_TIMEOUT") } } if finallyTimeoutStr != "" { @@ -292,7 +303,7 @@ func (r *IntegrationPipelineRun) WithDefaultIntegrationTimeouts(logger logr.Logg if err == nil { r.Spec.Timeouts.Finally = &metav1.Duration{Duration: finallyTimeout} } else { - logger.Error(err, "failed to parse default FINALLY_TIMEOUT") + logger.Error(err, "failed to parse the FINALLY_TIMEOUT") } } diff --git a/tekton/integration_pipeline_test.go b/tekton/integration_pipeline_test.go index 886a3467f..ba1f21b66 100644 --- a/tekton/integration_pipeline_test.go +++ b/tekton/integration_pipeline_test.go @@ -280,7 +280,7 @@ var _ = Describe("Integration pipeline", func() { It("can add timeouts to the IntegrationPipelineRun according to the environment variables", func() { var buf bytes.Buffer expectedDuration, _ := time.ParseDuration("2h") - newIntegrationPipelineRun.WithDefaultIntegrationTimeouts(buflogr.NewWithBuffer(&buf)) + newIntegrationPipelineRun.WithIntegrationTimeouts(integrationTestScenarioGit, buflogr.NewWithBuffer(&buf)) Expect(newIntegrationPipelineRun.Spec.Timeouts.Pipeline.Duration).To(Equal(expectedDuration)) Expect(newIntegrationPipelineRun.Spec.Timeouts.Tasks.Duration).To(Equal(expectedDuration)) @@ -290,7 +290,7 @@ var _ = Describe("Integration pipeline", func() { os.Setenv("PIPELINE_TIMEOUT", "") os.Setenv("TASKS_TIMEOUT", "") os.Setenv("FINALLY_TIMEOUT", "") - newIntegrationPipelineRun.WithDefaultIntegrationTimeouts(buflogr.NewWithBuffer(&buf)) + newIntegrationPipelineRun.WithIntegrationTimeouts(integrationTestScenarioGit, buflogr.NewWithBuffer(&buf)) Expect(newIntegrationPipelineRun.Spec.Timeouts.Pipeline).To(BeNil()) Expect(newIntegrationPipelineRun.Spec.Timeouts.Tasks).To(BeNil()) @@ -300,13 +300,51 @@ var _ = Describe("Integration pipeline", func() { os.Setenv("PIPELINE_TIMEOUT", "thisIsNotAValidDuration!") os.Setenv("TASKS_TIMEOUT", "thisIsNotAValidDuration!") os.Setenv("FINALLY_TIMEOUT", "thisIsNotAValidDuration!") - newIntegrationPipelineRun.WithDefaultIntegrationTimeouts(buflogr.NewWithBuffer(&buf)) + newIntegrationPipelineRun.WithIntegrationTimeouts(integrationTestScenarioGit, buflogr.NewWithBuffer(&buf)) Expect(newIntegrationPipelineRun.Spec.Timeouts.Pipeline).To(BeNil()) Expect(newIntegrationPipelineRun.Spec.Timeouts.Tasks).To(BeNil()) Expect(newIntegrationPipelineRun.Spec.Timeouts.Finally).To(BeNil()) - expectedLogEntryPrefix := "failed to parse default" + expectedLogEntryPrefix := "failed to parse the" + Expect(buf.String()).Should(ContainSubstring(expectedLogEntryPrefix + " PIPELINE_TIMEOUT")) + Expect(buf.String()).Should(ContainSubstring(expectedLogEntryPrefix + " TASKS_TIMEOUT")) + Expect(buf.String()).Should(ContainSubstring(expectedLogEntryPrefix + " FINALLY_TIMEOUT")) + }) + + It("can add timeouts to the IntegrationPipelineRun according to the integrationTestScenario annotations", func() { + var buf bytes.Buffer + // Use the environment variables by default, override if annotations are set + expectedDurationFromEnv, _ := time.ParseDuration("2h") + expectedDurationFromScenario, _ := time.ParseDuration("8h") + integrationTestScenarioGit.Annotations = map[string]string{} + integrationTestScenarioGit.Annotations[v1beta2.PipelineTimeoutAnnotation] = "8h" + newIntegrationPipelineRun.WithIntegrationTimeouts(integrationTestScenarioGit, buflogr.NewWithBuffer(&buf)) + + Expect(newIntegrationPipelineRun.Spec.Timeouts.Pipeline.Duration).To(Equal(expectedDurationFromScenario)) + Expect(newIntegrationPipelineRun.Spec.Timeouts.Tasks.Duration).To(Equal(expectedDurationFromEnv)) + Expect(newIntegrationPipelineRun.Spec.Timeouts.Finally.Duration).To(Equal(expectedDurationFromEnv)) + + // Override the environment if all annotations are set + integrationTestScenarioGit.Annotations[v1beta2.TasksTimeoutAnnotation] = "8h" + integrationTestScenarioGit.Annotations[v1beta2.FinallyTimeoutAnnotation] = "8h" + newIntegrationPipelineRun.WithIntegrationTimeouts(integrationTestScenarioGit, buflogr.NewWithBuffer(&buf)) + + Expect(newIntegrationPipelineRun.Spec.Timeouts.Pipeline.Duration).To(Equal(expectedDurationFromScenario)) + Expect(newIntegrationPipelineRun.Spec.Timeouts.Tasks.Duration).To(Equal(expectedDurationFromScenario)) + Expect(newIntegrationPipelineRun.Spec.Timeouts.Finally.Duration).To(Equal(expectedDurationFromScenario)) + + // Set the timeouts to invalid strings, which should skip setting the timeouts + integrationTestScenarioGit.Annotations[v1beta2.PipelineTimeoutAnnotation] = "thisIsNotAValidDuration!" + integrationTestScenarioGit.Annotations[v1beta2.TasksTimeoutAnnotation] = "thisIsNotAValidDuration!" + integrationTestScenarioGit.Annotations[v1beta2.FinallyTimeoutAnnotation] = "thisIsNotAValidDuration!" + newIntegrationPipelineRun.WithIntegrationTimeouts(integrationTestScenarioGit, buflogr.NewWithBuffer(&buf)) + + Expect(newIntegrationPipelineRun.Spec.Timeouts.Pipeline).To(BeNil()) + Expect(newIntegrationPipelineRun.Spec.Timeouts.Tasks).To(BeNil()) + Expect(newIntegrationPipelineRun.Spec.Timeouts.Finally).To(BeNil()) + + expectedLogEntryPrefix := "failed to parse the" Expect(buf.String()).Should(ContainSubstring(expectedLogEntryPrefix + " PIPELINE_TIMEOUT")) Expect(buf.String()).Should(ContainSubstring(expectedLogEntryPrefix + " TASKS_TIMEOUT")) Expect(buf.String()).Should(ContainSubstring(expectedLogEntryPrefix + " FINALLY_TIMEOUT"))