github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/tests/build/jvm-build.go (about) 1 package build 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "strings" 8 "time" 9 10 "sigs.k8s.io/controller-runtime/pkg/client" 11 12 "github.com/devfile/library/v2/pkg/util" 13 . "github.com/onsi/ginkgo/v2" 14 . "github.com/onsi/gomega" 15 appservice "github.com/redhat-appstudio/application-api/api/v1alpha1" 16 buildservice "github.com/redhat-appstudio/build-service/api/v1alpha1" 17 "github.com/redhat-appstudio/e2e-tests/pkg/clients/has" 18 "github.com/redhat-appstudio/e2e-tests/pkg/constants" 19 "github.com/redhat-appstudio/e2e-tests/pkg/framework" 20 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 21 "github.com/redhat-appstudio/e2e-tests/pkg/utils/tekton" 22 "github.com/redhat-appstudio/jvm-build-service/openshift-with-appstudio-test/e2e" 23 "github.com/redhat-appstudio/jvm-build-service/pkg/apis/jvmbuildservice/v1alpha1" 24 jvmclientSet "github.com/redhat-appstudio/jvm-build-service/pkg/client/clientset/versioned" 25 pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" 26 pipelineclientset "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" 27 "k8s.io/client-go/kubernetes" 28 29 corev1 "k8s.io/api/core/v1" 30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 "k8s.io/apimachinery/pkg/types" 32 ) 33 34 var ( 35 testProjectGitUrl = utils.GetEnv("JVM_BUILD_SERVICE_TEST_REPO_URL", "https://github.com/redhat-appstudio-qe/hacbs-test-project") 36 testProjectRevision = utils.GetEnv("JVM_BUILD_SERVICE_TEST_REPO_REVISION", "34da5a8f51fba6a8b7ec75a727d3c72ebb5e1274") 37 ) 38 39 var _ = framework.JVMBuildSuiteDescribe("JVM Build Service E2E tests", Label("jvm-build", "HACBS"), func() { 40 var f *framework.Framework 41 AfterEach(framework.ReportFailure(&f)) 42 var err error 43 44 defer GinkgoRecover() 45 46 var testNamespace, applicationName, componentName string 47 var component *appservice.Component 48 var timeout, interval time.Duration 49 50 AfterAll(func() { 51 jvmClient := jvmclientSet.New(f.AsKubeAdmin.JvmbuildserviceController.JvmbuildserviceClient().JvmbuildserviceV1alpha1().RESTClient()) 52 tektonClient := pipelineclientset.New(f.AsKubeAdmin.TektonController.PipelineClient().TektonV1().RESTClient()) 53 kubeClient := kubernetes.New(f.AsKubeAdmin.CommonController.KubeInterface().CoreV1().RESTClient()) 54 //status report ends up in artifacts/redhat-appstudio-e2e/redhat-appstudio-e2e/artifacts/rp_preproc/attachments/xunit 55 e2e.GenerateStatusReport(testNamespace, jvmClient, kubeClient, tektonClient) 56 if !CurrentSpecReport().Failed() { 57 Expect(f.AsKubeAdmin.HasController.DeleteComponent(componentName, testNamespace, false)).To(Succeed()) 58 Expect(f.AsKubeAdmin.HasController.DeleteApplication(applicationName, testNamespace, false)).To(Succeed()) 59 Expect(f.AsKubeAdmin.TektonController.DeleteAllPipelineRunsInASpecificNamespace(testNamespace)).To(Succeed()) 60 Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue()) 61 Expect(f.AsKubeAdmin.JvmbuildserviceController.DeleteJBSConfig(constants.JBSConfigName, testNamespace)).To(Succeed()) 62 } else { 63 Expect(f.AsKubeAdmin.CommonController.StoreAllPods(testNamespace)).To(Succeed()) 64 Expect(f.AsKubeAdmin.TektonController.StoreAllPipelineRuns(testNamespace)).To(Succeed()) 65 } 66 }) 67 68 BeforeAll(func() { 69 f, err = framework.NewFramework(utils.GetGeneratedNamespace("jvm-build")) 70 Expect(err).NotTo(HaveOccurred()) 71 testNamespace = f.UserNamespace 72 Expect(testNamespace).NotTo(BeNil(), "failed to create sandbox user namespace") 73 74 _, err = f.AsKubeAdmin.JvmbuildserviceController.CreateJBSConfig(constants.JBSConfigName, testNamespace) 75 Expect(err).ShouldNot(HaveOccurred()) 76 77 //TODO: not using SPI at the moment for auto created repos 78 //var SPITokenBinding *spi.SPIAccessTokenBinding 79 ////this should result in the creation of an SPIAccessTokenBinding 80 //Eventually(func() bool { 81 // SPITokenBinding, err = f.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(constants.JVMBuildImageSecretName, testNamespace) 82 // 83 // if err != nil { 84 // return false 85 // } 86 // 87 // return SPITokenBinding.Status.Phase == spi.SPIAccessTokenBindingPhaseInjected 88 //}, 1*time.Minute, 5*time.Second).Should(BeTrue(), "Access token binding should be created") 89 90 //wait for the cache 91 92 Expect(f.AsKubeAdmin.JvmbuildserviceController.WaitForCache(f.AsKubeAdmin.CommonController, testNamespace)).Should(Succeed()) 93 94 customJavaPipelineBundleRef := os.Getenv(constants.CUSTOM_JAVA_PIPELINE_BUILD_BUNDLE_ENV) 95 if len(customJavaPipelineBundleRef) > 0 { 96 ps := &buildservice.BuildPipelineSelector{ 97 ObjectMeta: metav1.ObjectMeta{ 98 Name: "build-pipeline-selector", 99 Namespace: testNamespace, 100 }, 101 Spec: buildservice.BuildPipelineSelectorSpec{Selectors: []buildservice.PipelineSelector{ 102 { 103 Name: "custom java selector", 104 PipelineRef: *tekton.NewBundleResolverPipelineRef("java-builder", customJavaPipelineBundleRef), 105 WhenConditions: buildservice.WhenCondition{Language: "java"}, 106 }, 107 }}, 108 } 109 Expect(f.AsKubeAdmin.CommonController.KubeRest().Create(context.Background(), ps)).To(Succeed()) 110 } 111 112 timeout = time.Minute * 20 113 interval = time.Second * 10 114 115 applicationName = fmt.Sprintf("jvm-build-suite-application-%s", util.GenerateRandomString(4)) 116 _, err = f.AsKubeAdmin.HasController.CreateApplication(applicationName, testNamespace) 117 Expect(err).NotTo(HaveOccurred()) 118 119 componentName = fmt.Sprintf("jvm-build-suite-component-%s", util.GenerateRandomString(6)) 120 121 // Create a component with Git Source URL being defined 122 componentObj := appservice.ComponentSpec{ 123 ComponentName: componentName, 124 Source: appservice.ComponentSource{ 125 ComponentSourceUnion: appservice.ComponentSourceUnion{ 126 GitSource: &appservice.GitSource{ 127 URL: testProjectGitUrl, 128 Revision: testProjectRevision, 129 }, 130 }, 131 }, 132 } 133 component, err = f.AsKubeAdmin.HasController.CreateComponent(componentObj, testNamespace, "", "", applicationName, true, map[string]string{}) 134 Expect(err).ShouldNot(HaveOccurred()) 135 }) 136 137 When("the Component with s2i-java component is created", func() { 138 It("a PipelineRun is triggered", func() { 139 Eventually(func() error { 140 pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "") 141 if err != nil { 142 GinkgoWriter.Printf("PipelineRun has not been created yet for the component %s/%s", testNamespace, componentName) 143 return err 144 } 145 if !pr.HasStarted() { 146 return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pr.GetNamespace(), pr.GetName()) 147 } 148 return nil 149 }, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the PipelineRun to start for the component %s/%s", testNamespace, componentName)) 150 }) 151 152 It("the build-container task from component pipelinerun references a correct analyzer image", func() { 153 ciAnalyzerImage := os.Getenv("JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE") 154 matchingTaskStep := "analyse-dependencies-java-sbom" 155 156 if ciAnalyzerImage == "" { 157 Skip("JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE env var is not exported, skipping the test...") 158 } 159 160 Eventually(func() error { 161 pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "") 162 Expect(err).ShouldNot(HaveOccurred()) 163 164 for _, chr := range pr.Status.ChildReferences { 165 taskRun := &pipeline.TaskRun{} 166 taskRunKey := types.NamespacedName{Namespace: pr.Namespace, Name: chr.Name} 167 err := f.AsKubeAdmin.CommonController.KubeRest().Get(context.Background(), taskRunKey, taskRun) 168 Expect(err).ShouldNot(HaveOccurred()) 169 170 prTrStatus := &pipeline.PipelineRunTaskRunStatus{ 171 PipelineTaskName: chr.PipelineTaskName, 172 Status: &taskRun.Status, 173 } 174 175 if chr.PipelineTaskName == constants.BuildTaskRunName && prTrStatus.Status != nil && prTrStatus.Status.TaskSpec != nil && prTrStatus.Status.TaskSpec.Steps != nil { 176 for _, step := range prTrStatus.Status.TaskSpec.Steps { 177 if step.Name == matchingTaskStep { 178 if step.Image != ciAnalyzerImage { 179 Fail(fmt.Sprintf("the build-container task from component pipelinerun doesn't reference the correct request processor image. expected: %v, actual: %v", ciAnalyzerImage, step.Image)) 180 } else { 181 return nil 182 } 183 } 184 } 185 } 186 } 187 return fmt.Errorf("couldn't find a matching step %s in task %s in PipelineRun %s/%s", matchingTaskStep, constants.BuildTaskRunName, testNamespace, pr.GetName()) 188 }, timeout, interval).Should(Succeed(), "timed out when verifying the request processor image reference in pipelinerun") 189 }) 190 191 It("that PipelineRun completes successfully", func() { 192 Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component, "", 193 f.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 2, Always: true}, nil)).To(Succeed()) 194 195 pr, err := f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "") 196 Expect(err).ShouldNot(HaveOccurred()) 197 //now delete it so it can't interfere with later test logic 198 Expect(f.AsKubeAdmin.TektonController.DeletePipelineRun(pr.Name, testNamespace)).Should(Succeed()) 199 }) 200 201 It("artifactbuilds and dependencybuilds are generated", func() { 202 Eventually(func() bool { 203 var gotABs, gotDBs bool 204 abList, err := f.AsKubeAdmin.JvmbuildserviceController.ListArtifactBuilds(testNamespace) 205 if err != nil { 206 GinkgoWriter.Printf("error listing artifactbuilds: %s\n", err.Error()) 207 return false 208 } 209 if len(abList.Items) > 0 { 210 gotABs = true 211 } 212 dbList, err := f.AsKubeAdmin.JvmbuildserviceController.ListDependencyBuilds(testNamespace) 213 if err != nil { 214 GinkgoWriter.Printf("error listing dependencybuilds: %s\n", err.Error()) 215 return false 216 } 217 if len(dbList.Items) > 0 { 218 gotDBs = true 219 } 220 GinkgoWriter.Printf("got artifactbuilds: %t, got dependencybuilds: %t\n", gotABs, gotDBs) 221 if !gotABs || !gotDBs { 222 return false 223 } 224 return true 225 }, timeout, interval).Should(BeTrue(), "timed out when waiting for the generation of artifactbuilds and dependencybuilds") 226 }) 227 228 It("some artifactbuilds and dependencybuilds complete", func() { 229 Eventually(func() bool { 230 var abComplete, dbComplete bool 231 abList, err := f.AsKubeAdmin.JvmbuildserviceController.ListArtifactBuilds(testNamespace) 232 if err != nil { 233 GinkgoWriter.Printf("error listing artifactbuilds: %s\n", err.Error()) 234 return false 235 } 236 for _, ab := range abList.Items { 237 if ab.Status.State == v1alpha1.ArtifactBuildStateComplete { 238 abComplete = true 239 break 240 } 241 } 242 dbList, err := f.AsKubeAdmin.JvmbuildserviceController.ListDependencyBuilds(testNamespace) 243 if err != nil { 244 GinkgoWriter.Printf("error listing dependencybuilds: %s\n", err.Error()) 245 return false 246 } 247 for _, db := range dbList.Items { 248 if db.Status.State == v1alpha1.DependencyBuildStateComplete { 249 dbComplete = true 250 break 251 } 252 } 253 GinkgoWriter.Printf("some artifactbuilds completed: %t, some dependencybuilds completed: %t\n", abComplete, dbComplete) 254 if !abComplete || !dbComplete { 255 return false 256 } 257 return true 258 }, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for some artifactbuilds and dependencybuilds to complete in %s namespace", testNamespace)) 259 }) 260 261 It("all artifactbuild and dependencybuilds complete", func() { 262 Eventually(func() bool { 263 abList, err := f.AsKubeAdmin.JvmbuildserviceController.ListArtifactBuilds(testNamespace) 264 Expect(err).ShouldNot(HaveOccurred(), "error in listing artifact builds") 265 // we want to make sure there is more than one ab and that they are all complete 266 allAbCompleted := len(abList.Items) > 0 267 GinkgoWriter.Printf("number of artifactbuilds: %d\n", len(abList.Items)) 268 for _, ab := range abList.Items { 269 if ab.Status.State != v1alpha1.ArtifactBuildStateComplete { 270 GinkgoWriter.Printf("artifactbuild %s not complete\n", ab.Spec.GAV) 271 allAbCompleted = false 272 break 273 } 274 } 275 dbList, err := f.AsKubeAdmin.JvmbuildserviceController.ListDependencyBuilds(testNamespace) 276 Expect(err).ShouldNot(HaveOccurred(), "error in listing dependency builds") 277 allDbCompleted := len(dbList.Items) > 0 278 GinkgoWriter.Printf("number of dependencybuilds: %d\n", len(dbList.Items)) 279 for _, db := range dbList.Items { 280 if db.Status.State != v1alpha1.DependencyBuildStateComplete { 281 GinkgoWriter.Printf("dependencybuild %s not complete\n", db.Spec.ScmInfo.SCMURL) 282 allDbCompleted = false 283 break 284 } else if db.Status.State == v1alpha1.DependencyBuildStateFailed { 285 Fail(fmt.Sprintf("dependencybuild %s FAILED", db.Spec.ScmInfo.SCMURL)) 286 } 287 } 288 if allAbCompleted && allDbCompleted { 289 return true 290 } 291 return false 292 }, 2*timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for all artifactbuilds and dependencybuilds to complete in %s namespace", testNamespace)) 293 }) 294 295 It("does rebuild using cached dependencies", func() { 296 prun := &pipeline.PipelineRun{} 297 298 component, err := f.AsKubeAdmin.HasController.GetComponent(componentName, testNamespace) 299 Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("could not get component %s/%s", testNamespace, componentName)) 300 301 annotations := utils.MergeMaps(component.GetAnnotations(), constants.ComponentTriggerSimpleBuildAnnotation) 302 component.SetAnnotations(annotations) 303 Expect(f.AsKubeAdmin.CommonController.KubeRest().Update(context.Background(), component, &client.UpdateOptions{})).To(Succeed()) 304 305 Eventually(func() error { 306 prun, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "") 307 return err 308 }, 1*time.Minute, constants.PipelineRunPollingInterval).Should(BeNil(), fmt.Sprintf("timed out when getting the pipelinerun for %s/%s component", testNamespace, componentName)) 309 310 ctx := context.Background() 311 312 watch, err := f.AsKubeAdmin.TektonController.GetPipelineRunWatch(ctx, testNamespace) 313 Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("watch pipelinerun failed in %s namespace", testNamespace)) 314 315 exitForLoop := false 316 317 for { 318 select { 319 case <-time.After(15 * time.Minute): 320 Fail(fmt.Sprintf("timed out waiting for second build to complete in %s namespace", testNamespace)) 321 case event := <-watch.ResultChan(): 322 if event.Object == nil { 323 continue 324 } 325 pr, ok := event.Object.(*pipeline.PipelineRun) 326 if !ok { 327 continue 328 } 329 if prun.Name != pr.Name { 330 if pr.IsDone() { 331 GinkgoWriter.Printf("got event for pipelinerun %s in a terminal state\n", pr.GetName()) 332 continue 333 } 334 Fail(fmt.Sprintf("another non-completed pipeline run %s/%s was generated when it should not", pr.GetNamespace(), pr.GetName())) 335 } 336 GinkgoWriter.Printf("done processing event for pr %s\n", pr.GetName()) 337 if pr.IsDone() { 338 GinkgoWriter.Println("pr is done") 339 340 podClient := f.AsKubeAdmin.CommonController.KubeInterface().CoreV1().Pods(testNamespace) 341 listOptions := metav1.ListOptions{ 342 LabelSelector: fmt.Sprintf("tekton.dev/pipelineRun=%s", pr.GetName()), 343 } 344 podList, err := podClient.List(context.Background(), listOptions) 345 Expect(err).ShouldNot(HaveOccurred(), "error listing pr pods") 346 347 pods := podList.Items 348 349 if len(pods) == 0 { 350 Fail(fmt.Sprintf("pod for pipeline run %s/%s unexpectedly missing", pr.GetNamespace(), pr.GetName())) 351 } 352 353 containers := []corev1.Container{} 354 containers = append(containers, pods[0].Spec.InitContainers...) 355 containers = append(containers, pods[0].Spec.Containers...) 356 357 for _, container := range containers { 358 if !strings.Contains(container.Name, "analyse-dependecies") { 359 continue 360 } 361 cLog, err := utils.GetContainerLogs(f.AsKubeAdmin.CommonController.KubeInterface(), pods[0].Name, container.Name, testNamespace) 362 Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("getting container logs for %s container from %s pod in %s namespace failed", container.Name, pods[0].GetName(), testNamespace)) 363 if strings.Contains(cLog, "\"publisher\" : \"central\"") { 364 Fail(fmt.Sprintf("pipelinerun %s has container %s with dep analysis still pointing to central %s", pr.Name, container.Name, cLog)) 365 } 366 if !strings.Contains(cLog, "\"publisher\" : \"rebuilt\"") { 367 Fail(fmt.Sprintf("pipelinerun %s has container %s with dep analysis that does not access rebuilt %s", pr.Name, container.Name, cLog)) 368 } 369 if !strings.Contains(cLog, "\"java:scm-uri\" : \"https://github.com/stuartwdouglas/hacbs-test-simple-jdk8.git\"") { 370 Fail(fmt.Sprintf("pipelinerun %s has container %s with dep analysis did not include java:scm-uri %s", pr.Name, container.Name, cLog)) 371 } 372 if !strings.Contains(cLog, "\"java:scm-commit\" : \"") { 373 Fail(fmt.Sprintf("pipelinerun %s has container %s with dep analysis did not include java:scm-commit %s", pr.Name, container.Name, cLog)) 374 } 375 break 376 } 377 GinkgoWriter.Println("pr is done and has correct analyse-dependecies output, exiting") 378 exitForLoop = true 379 } 380 } 381 if exitForLoop { 382 break 383 } 384 } 385 }) 386 387 It("All rebuilt images are signed and attested", func() { 388 seen := map[string]bool{} 389 rebuilt, err := f.AsKubeAdmin.JvmbuildserviceController.ListRebuiltArtifacts(testNamespace) 390 Expect(err).NotTo(HaveOccurred()) 391 for _, i := range rebuilt.Items { 392 if seen[i.Spec.Image] { 393 continue 394 } 395 seen[i.Spec.Image] = true 396 397 imageWithDigest := i.Spec.Image + "@" + i.Spec.Digest 398 399 Expect(f.AsKubeAdmin.TektonController.AwaitAttestationAndSignature(imageWithDigest, constants.ChainsAttestationTimeout)).To( 400 Succeed(), 401 "Could not find .att or .sig ImageStreamTags within the 1 minute timeout. "+ 402 "Most likely the chains-controller did not create those in time. "+ 403 "Look at the chains-controller logs.") 404 GinkgoWriter.Printf("Cosign verify pass with .att and .sig ImageStreamTags found for %s\n", imageWithDigest) 405 406 } 407 }) 408 }) 409 })