github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/tests/integration-service/integration.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/konflux-ci/operator-toolkit/metadata" 8 9 "github.com/devfile/library/v2/pkg/util" 10 "github.com/redhat-appstudio/e2e-tests/pkg/clients/has" 11 "github.com/redhat-appstudio/e2e-tests/pkg/framework" 12 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 13 pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" 14 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 15 16 integrationv1beta1 "github.com/konflux-ci/integration-service/api/v1beta1" 17 intgteststat "github.com/konflux-ci/integration-service/pkg/integrationteststatus" 18 19 appstudioApi "github.com/redhat-appstudio/application-api/api/v1alpha1" 20 21 . "github.com/onsi/ginkgo/v2" 22 . "github.com/onsi/gomega" 23 ) 24 25 var _ = framework.IntegrationServiceSuiteDescribe("Integration Service E2E tests", Label("integration-service", "HACBS"), func() { 26 defer GinkgoRecover() 27 28 var f *framework.Framework 29 var err error 30 31 var applicationName, componentName, testNamespace string 32 var integrationTestScenario *integrationv1beta1.IntegrationTestScenario 33 var newIntegrationTestScenario *integrationv1beta1.IntegrationTestScenario 34 var timeout, interval time.Duration 35 var originalComponent *appstudioApi.Component 36 var pipelineRun *pipeline.PipelineRun 37 var snapshot *appstudioApi.Snapshot 38 var snapshotPush *appstudioApi.Snapshot 39 AfterEach(framework.ReportFailure(&f)) 40 41 Describe("with happy path for general flow of Integration service", Ordered, func() { 42 BeforeAll(func() { 43 // Initialize the tests controllers 44 f, err = framework.NewFramework(utils.GetGeneratedNamespace("integration1")) 45 Expect(err).NotTo(HaveOccurred()) 46 testNamespace = f.UserNamespace 47 48 applicationName = createApp(*f, testNamespace) 49 componentName, originalComponent = createComponent(*f, testNamespace, applicationName) 50 integrationTestScenario, err = f.AsKubeAdmin.IntegrationController.CreateIntegrationTestScenario("", applicationName, testNamespace, gitURL, revision, pathInRepoPass) 51 Expect(err).ShouldNot(HaveOccurred()) 52 }) 53 54 AfterAll(func() { 55 if !CurrentSpecReport().Failed() { 56 cleanup(*f, testNamespace, applicationName, componentName) 57 58 Expect(f.AsKubeAdmin.IntegrationController.DeleteSnapshot(snapshotPush, testNamespace)).To(Succeed()) 59 } 60 }) 61 62 When("a new Component is created", func() { 63 It("triggers a build PipelineRun", Label("integration-service"), func() { 64 pipelineRun, err = f.AsKubeDeveloper.IntegrationController.GetBuildPipelineRun(componentName, applicationName, testNamespace, false, "") 65 Expect(err).ShouldNot(HaveOccurred()) 66 }) 67 68 It("verifies if the build PipelineRun contains the finalizer", Label("integration-service"), func() { 69 Eventually(func() error { 70 pipelineRun, err = f.AsKubeDeveloper.IntegrationController.GetBuildPipelineRun(componentName, applicationName, testNamespace, false, "") 71 Expect(err).ShouldNot(HaveOccurred()) 72 if !controllerutil.ContainsFinalizer(pipelineRun, pipelinerunFinalizerByIntegrationService) { 73 return fmt.Errorf("build pipelineRun %s/%s doesn't contain the finalizer: %s yet", pipelineRun.GetNamespace(), pipelineRun.GetName(), pipelinerunFinalizerByIntegrationService) 74 } 75 return nil 76 }, 1*time.Minute, 1*time.Second).Should(Succeed(), "timeout when waiting for finalizer to be added") 77 }) 78 79 It("waits for build PipelineRun to succeed", Label("integration-service"), func() { 80 Expect(pipelineRun.Annotations[snapshotAnnotation]).To(Equal("")) 81 Expect(f.AsKubeDeveloper.HasController.WaitForComponentPipelineToBeFinished(originalComponent, "", 82 f.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 2, Always: true}, pipelineRun)).To(Succeed()) 83 }) 84 }) 85 86 When("the build pipelineRun run succeeded", func() { 87 It("checks if the BuildPipelineRun have the annotation of chains signed", func() { 88 Expect(f.AsKubeDeveloper.IntegrationController.WaitForBuildPipelineRunToGetAnnotated(testNamespace, applicationName, componentName, chainsSignedAnnotation)).To(Succeed()) 89 }) 90 91 It("checks if the Snapshot is created", func() { 92 snapshot, err = f.AsKubeDeveloper.IntegrationController.WaitForSnapshotToGetCreated("", "", componentName, testNamespace) 93 Expect(err).ShouldNot(HaveOccurred()) 94 }) 95 96 It("checks if the Build PipelineRun got annotated with Snapshot name", func() { 97 Expect(f.AsKubeDeveloper.IntegrationController.WaitForBuildPipelineRunToGetAnnotated(testNamespace, applicationName, componentName, snapshotAnnotation)).To(Succeed()) 98 }) 99 100 It("verifies that the finalizer has been removed from the build pipelinerun", func() { 101 timeout := "60s" 102 interval := "1s" 103 Eventually(func() error { 104 pipelineRun, err = f.AsKubeDeveloper.IntegrationController.GetBuildPipelineRun(componentName, applicationName, testNamespace, false, "") 105 Expect(err).ShouldNot(HaveOccurred()) 106 if controllerutil.ContainsFinalizer(pipelineRun, pipelinerunFinalizerByIntegrationService) { 107 return fmt.Errorf("build pipelineRun %s/%s still contains the finalizer: %s", pipelineRun.GetNamespace(), pipelineRun.GetName(), pipelinerunFinalizerByIntegrationService) 108 } 109 return nil 110 }, timeout, interval).Should(Succeed(), "timeout when waiting for finalizer to be removed") 111 }) 112 113 It("checks if all of the integrationPipelineRuns passed", Label("slow"), func() { 114 Expect(f.AsKubeDeveloper.IntegrationController.WaitForAllIntegrationPipelinesToBeFinished(testNamespace, applicationName, snapshot)).To(Succeed()) 115 }) 116 117 It("checks if the passed status of integration test is reported in the Snapshot", func() { 118 timeout = time.Second * 240 119 interval = time.Second * 5 120 Eventually(func() error { 121 snapshot, err = f.AsKubeAdmin.IntegrationController.GetSnapshot(snapshot.Name, "", "", testNamespace) 122 Expect(err).ShouldNot(HaveOccurred()) 123 124 statusDetail, err := f.AsKubeDeveloper.IntegrationController.GetIntegrationTestStatusDetailFromSnapshot(snapshot, integrationTestScenario.Name) 125 Expect(err).ToNot(HaveOccurred()) 126 127 if statusDetail.Status != intgteststat.IntegrationTestStatusTestPassed { 128 return fmt.Errorf("test status for scenario: %s, doesn't have expected value %s, within the snapshot: %s", integrationTestScenario.Name, intgteststat.IntegrationTestStatusTestPassed, snapshot.Name) 129 } 130 return nil 131 }, timeout, interval).Should(Succeed()) 132 }) 133 134 It("checks if the finalizer was removed from all of the related Integration pipelineRuns", func() { 135 Expect(f.AsKubeDeveloper.IntegrationController.WaitForFinalizerToGetRemovedFromAllIntegrationPipelineRuns(testNamespace, applicationName, snapshot)).To(Succeed()) 136 }) 137 }) 138 139 It("creates a ReleasePlan", func() { 140 _, err = f.AsKubeAdmin.ReleaseController.CreateReleasePlan(autoReleasePlan, testNamespace, applicationName, targetReleaseNamespace, "", nil) 141 Expect(err).ShouldNot(HaveOccurred()) 142 testScenarios, err := f.AsKubeAdmin.IntegrationController.GetIntegrationTestScenarios(applicationName, testNamespace) 143 Expect(err).ShouldNot(HaveOccurred()) 144 for _, testScenario := range *testScenarios { 145 GinkgoWriter.Printf("IntegrationTestScenario %s is found\n", testScenario.Name) 146 } 147 }) 148 149 It("creates an snapshot of push event", func() { 150 sampleImage := "quay.io/redhat-appstudio/sample-image@sha256:841328df1b9f8c4087adbdcfec6cc99ac8308805dea83f6d415d6fb8d40227c1" 151 snapshotPush, err = f.AsKubeAdmin.IntegrationController.CreateSnapshotWithImage(componentName, applicationName, testNamespace, sampleImage) 152 Expect(err).ShouldNot(HaveOccurred()) 153 }) 154 155 When("An snapshot of push event is created", func() { 156 It("checks if all of the integrationPipelineRuns created by push event passed", Label("slow"), func() { 157 Expect(f.AsKubeAdmin.IntegrationController.WaitForAllIntegrationPipelinesToBeFinished(testNamespace, applicationName, snapshotPush)).To(Succeed(), "Error when waiting for one of the integration pipelines to finish in %s namespace", testNamespace) 158 }) 159 160 It("checks if the global candidate is updated after push event", func() { 161 timeout = time.Second * 600 162 interval = time.Second * 10 163 Eventually(func() error { 164 snapshotPush, err = f.AsKubeAdmin.IntegrationController.GetSnapshot(snapshotPush.Name, "", "", testNamespace) 165 Expect(err).ShouldNot(HaveOccurred()) 166 167 if f.AsKubeAdmin.CommonController.HaveTestsSucceeded(snapshotPush) { 168 component, err := f.AsKubeAdmin.HasController.GetComponentByApplicationName(applicationName, testNamespace) 169 Expect(err).ShouldNot(HaveOccurred()) 170 Expect(component.Spec.ContainerImage).ToNot(Equal(originalComponent.Spec.ContainerImage)) 171 return nil 172 } 173 return fmt.Errorf("tests haven't succeeded yet for snapshot %s/%s", snapshotPush.GetNamespace(), snapshotPush.GetName()) 174 }, timeout, interval).Should(Succeed(), fmt.Sprintf("time out when waiting for updating the global candidate in %s namespace", testNamespace)) 175 }) 176 177 It("checks if a Release is created successfully", func() { 178 timeout = time.Second * 60 179 interval = time.Second * 5 180 Eventually(func() error { 181 _, err := f.AsKubeAdmin.ReleaseController.GetReleases(testNamespace) 182 return err 183 }, timeout, interval).Should(Succeed(), fmt.Sprintf("time out when waiting for release created for snapshot %s/%s", snapshotPush.GetNamespace(), snapshotPush.GetName())) 184 }) 185 }) 186 }) 187 188 Describe("with an integration test fail", Ordered, func() { 189 BeforeAll(func() { 190 // Initialize the tests controllers 191 f, err = framework.NewFramework(utils.GetGeneratedNamespace("integration2")) 192 Expect(err).NotTo(HaveOccurred()) 193 testNamespace = f.UserNamespace 194 195 applicationName = createApp(*f, testNamespace) 196 componentName, originalComponent = createComponent(*f, testNamespace, applicationName) 197 198 integrationTestScenario, err = f.AsKubeAdmin.IntegrationController.CreateIntegrationTestScenario("", applicationName, testNamespace, gitURL, revision, pathInRepoFail) 199 Expect(err).ShouldNot(HaveOccurred()) 200 }) 201 202 AfterAll(func() { 203 if !CurrentSpecReport().Failed() { 204 cleanup(*f, testNamespace, applicationName, componentName) 205 206 } 207 }) 208 209 It("triggers a build PipelineRun", Label("integration-service"), func() { 210 pipelineRun, err = f.AsKubeDeveloper.IntegrationController.GetBuildPipelineRun(componentName, applicationName, testNamespace, false, "") 211 Expect(pipelineRun.Annotations[snapshotAnnotation]).To(Equal("")) 212 Expect(f.AsKubeDeveloper.HasController.WaitForComponentPipelineToBeFinished(originalComponent, "", f.AsKubeAdmin.TektonController, 213 &has.RetryOptions{Retries: 2, Always: true}, pipelineRun)).To(Succeed()) 214 215 }) 216 217 It("checks if the BuildPipelineRun have the annotation of chains signed", func() { 218 Expect(f.AsKubeDeveloper.IntegrationController.WaitForBuildPipelineRunToGetAnnotated(testNamespace, applicationName, componentName, chainsSignedAnnotation)).To(Succeed()) 219 }) 220 221 It("checks if the Snapshot is created", func() { 222 snapshot, err = f.AsKubeDeveloper.IntegrationController.WaitForSnapshotToGetCreated("", pipelineRun.Name, componentName, testNamespace) 223 Expect(err).ShouldNot(HaveOccurred()) 224 }) 225 226 It("checks if the Build PipelineRun got annotated with Snapshot name", func() { 227 Expect(f.AsKubeDeveloper.IntegrationController.WaitForBuildPipelineRunToGetAnnotated(testNamespace, applicationName, componentName, snapshotAnnotation)).To(Succeed()) 228 }) 229 230 It("checks if all of the integrationPipelineRuns finished", Label("slow"), func() { 231 Expect(f.AsKubeDeveloper.IntegrationController.WaitForAllIntegrationPipelinesToBeFinished(testNamespace, applicationName, snapshot)).To(Succeed()) 232 }) 233 234 It("checks if the failed status of integration test is reported in the Snapshot", func() { 235 Eventually(func() error { 236 snapshot, err = f.AsKubeAdmin.IntegrationController.GetSnapshot(snapshot.Name, "", "", testNamespace) 237 Expect(err).ShouldNot(HaveOccurred()) 238 239 statusDetail, err := f.AsKubeDeveloper.IntegrationController.GetIntegrationTestStatusDetailFromSnapshot(snapshot, integrationTestScenario.Name) 240 Expect(err).ToNot(HaveOccurred()) 241 242 if statusDetail.Status != intgteststat.IntegrationTestStatusTestFail { 243 return fmt.Errorf("test status doesn't have expected value %s", intgteststat.IntegrationTestStatusTestFail) 244 } 245 return nil 246 }, timeout, interval).Should(Succeed()) 247 }) 248 249 It("checks if snapshot is marked as failed", FlakeAttempts(3), func() { 250 snapshot, err = f.AsKubeAdmin.IntegrationController.GetSnapshot(snapshot.Name, "", "", testNamespace) 251 Expect(err).ShouldNot(HaveOccurred()) 252 Expect(f.AsKubeAdmin.CommonController.HaveTestsSucceeded(snapshot)).To(BeFalse(), "expected tests to fail for snapshot %s/%s", snapshot.GetNamespace(), snapshot.GetName()) 253 }) 254 255 It("checks if the finalizer was removed from all of the related Integration pipelineRuns", func() { 256 Expect(f.AsKubeDeveloper.IntegrationController.WaitForFinalizerToGetRemovedFromAllIntegrationPipelineRuns(testNamespace, applicationName, snapshot)).To(Succeed()) 257 }) 258 259 It("creates a new IntegrationTestScenario", func() { 260 newIntegrationTestScenario, err = f.AsKubeAdmin.IntegrationController.CreateIntegrationTestScenario("", applicationName, testNamespace, gitURL, revision, pathInRepoPass) 261 Expect(err).ShouldNot(HaveOccurred()) 262 }) 263 264 It("updates the Snapshot with the re-run label for the new scenario", FlakeAttempts(3), func() { 265 updatedSnapshot := snapshot.DeepCopy() 266 err := metadata.AddLabels(updatedSnapshot, map[string]string{snapshotRerunLabel: newIntegrationTestScenario.Name}) 267 Expect(err).ShouldNot(HaveOccurred()) 268 Expect(f.AsKubeAdmin.IntegrationController.PatchSnapshot(snapshot, updatedSnapshot)).Should(Succeed()) 269 Expect(metadata.GetLabelsWithPrefix(updatedSnapshot, snapshotRerunLabel)).NotTo(BeEmpty()) 270 }) 271 272 When("An snapshot is updated with a re-run label for a given scenario", func() { 273 It("checks if the new integration pipelineRun started", Label("slow"), func() { 274 reRunPipelineRun, err := f.AsKubeDeveloper.IntegrationController.WaitForIntegrationPipelineToGetStarted(newIntegrationTestScenario.Name, snapshot.Name, testNamespace) 275 Expect(err).ShouldNot(HaveOccurred()) 276 Expect(reRunPipelineRun).ShouldNot(BeNil()) 277 }) 278 279 It("checks if the re-run label was removed from the Snapshot", func() { 280 Eventually(func() error { 281 snapshot, err = f.AsKubeAdmin.IntegrationController.GetSnapshot(snapshot.Name, "", "", testNamespace) 282 if err != nil { 283 return fmt.Errorf("encountered error while getting Snapshot %s/%s: %w", snapshot.Name, snapshot.Namespace, err) 284 } 285 286 if metadata.HasLabel(snapshot, snapshotRerunLabel) { 287 return fmt.Errorf("the Snapshot %s/%s shouldn't contain the %s label", snapshot.Name, snapshot.Namespace, snapshotRerunLabel) 288 } 289 return nil 290 }, timeout, interval).Should(Succeed()) 291 }) 292 293 It("checks if all integration pipelineRuns finished successfully", Label("slow"), func() { 294 Expect(f.AsKubeDeveloper.IntegrationController.WaitForAllIntegrationPipelinesToBeFinished(testNamespace, applicationName, snapshot)).To(Succeed()) 295 }) 296 297 It("checks if the name of the re-triggered pipelinerun is reported in the Snapshot", FlakeAttempts(3), func() { 298 Eventually(func(g Gomega) { 299 snapshot, err = f.AsKubeAdmin.IntegrationController.GetSnapshot(snapshot.Name, "", "", testNamespace) 300 g.Expect(err).ShouldNot(HaveOccurred()) 301 302 statusDetail, err := f.AsKubeDeveloper.IntegrationController.GetIntegrationTestStatusDetailFromSnapshot(snapshot, newIntegrationTestScenario.Name) 303 g.Expect(err).ToNot(HaveOccurred()) 304 g.Expect(statusDetail).NotTo(BeNil()) 305 306 integrationPipelineRun, err := f.AsKubeDeveloper.IntegrationController.GetIntegrationPipelineRun(newIntegrationTestScenario.Name, snapshot.Name, testNamespace) 307 g.Expect(err).ToNot(HaveOccurred()) 308 g.Expect(integrationPipelineRun).NotTo(BeNil()) 309 310 g.Expect(statusDetail.TestPipelineRunName).To(Equal(integrationPipelineRun.Name)) 311 }, timeout, interval).Should(Succeed()) 312 }) 313 314 It("checks if snapshot is still marked as failed", func() { 315 snapshot, err = f.AsKubeAdmin.IntegrationController.GetSnapshot(snapshot.Name, "", "", testNamespace) 316 Expect(err).ShouldNot(HaveOccurred()) 317 Expect(f.AsKubeAdmin.CommonController.HaveTestsSucceeded(snapshot)).To(BeFalse(), "expected tests to fail for snapshot %s/%s", snapshot.GetNamespace(), snapshot.GetName()) 318 }) 319 320 }) 321 322 It("creates an snapshot of push event", func() { 323 sampleImage := "quay.io/redhat-appstudio/sample-image@sha256:841328df1b9f8c4087adbdcfec6cc99ac8308805dea83f6d415d6fb8d40227c1" 324 snapshotPush, err = f.AsKubeAdmin.IntegrationController.CreateSnapshotWithImage(componentName, applicationName, testNamespace, sampleImage) 325 Expect(err).ShouldNot(HaveOccurred()) 326 }) 327 328 When("An snapshot of push event is created", func() { 329 It("checks no Release CRs are created", func() { 330 releases, err := f.AsKubeAdmin.ReleaseController.GetReleases(testNamespace) 331 Expect(err).NotTo(HaveOccurred(), "Error when fetching the Releases") 332 Expect(releases.Items).To(BeEmpty(), "Expected no Release CRs to be present, but found some") 333 }) 334 335 It("checks if the global candidate is not updated", func() { 336 // give some time to do eventual updates in component 337 time.Sleep(60 * time.Second) 338 339 component, err := f.AsKubeAdmin.HasController.GetComponentByApplicationName(applicationName, testNamespace) 340 Expect(err).ShouldNot(HaveOccurred()) 341 342 // global candidate is not updated 343 Expect(component.Spec.ContainerImage).To(Equal(originalComponent.Spec.ContainerImage)) 344 }) 345 }) 346 }) 347 }) 348 349 func createApp(f framework.Framework, testNamespace string) string { 350 applicationName := fmt.Sprintf("integ-app-%s", util.GenerateRandomString(4)) 351 352 _, err := f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace) 353 Expect(err).NotTo(HaveOccurred()) 354 355 return applicationName 356 } 357 358 func createComponent(f framework.Framework, testNamespace, applicationName string) (string, *appstudioApi.Component) { 359 var originalComponent *appstudioApi.Component 360 361 componentName := fmt.Sprintf("integration-suite-test-component-git-source-%s", util.GenerateRandomString(6)) 362 // Create a component with Git Source URL being defined 363 // using cdq since git ref is not known 364 cdq, err := f.AsKubeAdmin.HasController.CreateComponentDetectionQuery(componentName, testNamespace, componentRepoURL, "", "", "", false) 365 Expect(err).NotTo(HaveOccurred()) 366 Expect(cdq.Status.ComponentDetected).To(HaveLen(1), "Expected length of the detected Components was not 1") 367 368 for _, compDetected := range cdq.Status.ComponentDetected { 369 originalComponent, err = f.AsKubeAdmin.HasController.CreateComponent(compDetected.ComponentStub, testNamespace, "", "", applicationName, true, map[string]string{}) 370 Expect(err).NotTo(HaveOccurred()) 371 Expect(originalComponent).NotTo(BeNil()) 372 componentName = originalComponent.Name 373 } 374 375 return componentName, originalComponent 376 } 377 378 func cleanup(f framework.Framework, testNamespace, applicationName, componentName string) { 379 if !CurrentSpecReport().Failed() { 380 Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed()) 381 Expect(f.AsKubeAdmin.HasController.DeleteComponent(componentName, testNamespace, false)).To(Succeed()) 382 integrationTestScenarios, err := f.AsKubeAdmin.IntegrationController.GetIntegrationTestScenarios(applicationName, testNamespace) 383 Expect(err).ShouldNot(HaveOccurred()) 384 385 for _, testScenario := range *integrationTestScenarios { 386 Expect(f.AsKubeAdmin.IntegrationController.DeleteIntegrationTestScenario(&testScenario, testNamespace)).To(Succeed()) 387 } 388 Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue()) 389 } 390 }