github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/tests/rhtap-demo/rhtap-demo.go (about)

     1  package rhtap_demo
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"strings"
     9  	"time"
    10  
    11  	buildcontrollers "github.com/redhat-appstudio/build-service/controllers"
    12  	tektonutils "github.com/redhat-appstudio/release-service/tekton/utils"
    13  
    14  	"github.com/redhat-appstudio/jvm-build-service/openshift-with-appstudio-test/e2e"
    15  	jvmclientSet "github.com/redhat-appstudio/jvm-build-service/pkg/client/clientset/versioned"
    16  	pipelineclientset "github.com/tektoncd/pipeline/pkg/client/clientset/versioned"
    17  	"k8s.io/client-go/kubernetes"
    18  
    19  	"github.com/devfile/library/v2/pkg/util"
    20  	ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1"
    21  	"github.com/google/go-github/v44/github"
    22  	. "github.com/onsi/ginkgo/v2"
    23  	. "github.com/onsi/gomega"
    24  	appservice "github.com/redhat-appstudio/application-api/api/v1alpha1"
    25  	"github.com/redhat-appstudio/e2e-tests/pkg/clients/has"
    26  	"github.com/redhat-appstudio/e2e-tests/pkg/constants"
    27  	"github.com/redhat-appstudio/e2e-tests/pkg/framework"
    28  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    29  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/build"
    30  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/tekton"
    31  	"github.com/redhat-appstudio/jvm-build-service/pkg/apis/jvmbuildservice/v1alpha1"
    32  	corev1 "k8s.io/api/core/v1"
    33  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    34  
    35  	releasecommon "github.com/redhat-appstudio/e2e-tests/tests/release"
    36  	integrationv1beta1 "github.com/konflux-ci/integration-service/api/v1beta1"
    37  	releaseApi "github.com/redhat-appstudio/release-service/api/v1alpha1"
    38  	tektonapi "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
    39  
    40  	e2eConfig "github.com/redhat-appstudio/e2e-tests/tests/rhtap-demo/config"
    41  )
    42  
    43  const (
    44  
    45  	// Secret Name created by spi to interact with github
    46  	SPIGithubSecretName string = "e2e-github-secret"
    47  
    48  	// Environment name used for e2e-tests demos
    49  	SPIQuaySecretName string = "e2e-quay-secret"
    50  
    51  	// Timeouts
    52  	appDeployTimeout            = time.Minute * 20
    53  	appRouteAvailableTimeout    = time.Minute * 5
    54  	customResourceUpdateTimeout = time.Minute * 10
    55  	jvmRebuildTimeout           = time.Minute * 40
    56  	mergePRTimeout              = time.Minute * 1
    57  	pipelineRunStartedTimeout   = time.Minute * 5
    58  	pullRequestCreationTimeout  = time.Minute * 5
    59  	releasePipelineTimeout      = time.Minute * 15
    60  	snapshotTimeout             = time.Minute * 4
    61  	releaseTimeout              = time.Minute * 4
    62  	testPipelineTimeout         = time.Minute * 15
    63  	branchCreateTimeout         = time.Minute * 1
    64  
    65  	// Intervals
    66  	defaultPollingInterval    = time.Second * 2
    67  	jvmRebuildPollingInterval = time.Second * 10
    68  	snapshotPollingInterval   = time.Second * 1
    69  	releasePollingInterval    = time.Second * 1
    70  
    71  	// test metadata
    72  	devEnvTestLabel = "rhtap-demo"
    73  
    74  	// stage env test related env vars
    75  	stageTimeout      = time.Minute * 5
    76  	stageEnvTestLabel = "verify-stage"
    77  )
    78  
    79  var supportedRuntimes = []string{"Dockerfile", "Node.js", "Go", "Quarkus", "Python", "JavaScript", "springboot", "dotnet", "maven"}
    80  
    81  var _ = framework.RhtapDemoSuiteDescribe(func() {
    82  	defer GinkgoRecover()
    83  
    84  	var timeout, interval time.Duration
    85  	var namespace string
    86  	var err error
    87  
    88  	// Initialize the application struct
    89  	application := &appservice.Application{}
    90  	snapshot := &appservice.Snapshot{}
    91  
    92  	fw := &framework.Framework{}
    93  	AfterEach(framework.ReportFailure(&fw))
    94  	var token, ssourl, apiurl string
    95  	var TestScenarios []e2eConfig.TestSpec
    96  
    97  	if strings.Contains(GinkgoLabelFilter(), stageEnvTestLabel) {
    98  		TestScenarios = append(TestScenarios, e2eConfig.GetScenarios(true)...)
    99  	} else {
   100  		TestScenarios = append(TestScenarios, e2eConfig.GetScenarios(false)...)
   101  	}
   102  
   103  	for _, appTest := range TestScenarios {
   104  		appTest := appTest
   105  		if !appTest.Skip {
   106  
   107  			Describe(appTest.Name, Ordered, func() {
   108  				BeforeAll(func() {
   109  					if strings.Contains(GinkgoLabelFilter(), stageEnvTestLabel) {
   110  						token = utils.GetEnv("STAGEUSER_TOKEN", "")
   111  						ssourl = utils.GetEnv("STAGE_SSOURL", "")
   112  						apiurl = utils.GetEnv("STAGE_APIURL", "")
   113  						username := utils.GetEnv("STAGE_USERNAME", "")
   114  						fw, err = framework.NewFrameworkWithTimeout(username, stageTimeout, utils.Options{
   115  							ToolchainApiUrl: apiurl,
   116  							KeycloakUrl:     ssourl,
   117  							OfflineToken:    token,
   118  						})
   119  					} else {
   120  						fw, err = framework.NewFramework(utils.GetGeneratedNamespace(devEnvTestLabel))
   121  					}
   122  					Expect(err).NotTo(HaveOccurred())
   123  					namespace = fw.UserNamespace
   124  					Expect(err).NotTo(HaveOccurred())
   125  
   126  					suiteConfig, _ := GinkgoConfiguration()
   127  					GinkgoWriter.Printf("Parallel processes: %d\n", suiteConfig.ParallelTotal)
   128  					GinkgoWriter.Printf("Running on namespace: %s\n", namespace)
   129  					GinkgoWriter.Printf("User: %s\n", fw.UserName)
   130  				})
   131  
   132  				// Remove all resources created by the tests
   133  				AfterAll(func() {
   134  					if !appTest.Stage {
   135  						// collect SPI ResourceQuota metrics (temporary)
   136  						err := fw.AsKubeAdmin.CommonController.GetResourceQuotaInfo(devEnvTestLabel, namespace, "appstudio-crds-spi")
   137  						Expect(err).NotTo(HaveOccurred())
   138  
   139  						if !(strings.EqualFold(os.Getenv("E2E_SKIP_CLEANUP"), "true")) && !CurrentSpecReport().Failed() { // RHTAPBUGS-978: temporary timeout to 15min
   140  							if err := fw.AsKubeAdmin.HasController.DeleteAllComponentsInASpecificNamespace(namespace, 15*time.Minute); err != nil {
   141  								if err := fw.AsKubeAdmin.StoreAllArtifactsForNamespace(namespace); err != nil {
   142  									Fail(fmt.Sprintf("error archiving artifacts:\n%s", err))
   143  								}
   144  								Fail(fmt.Sprintf("error deleting all componentns in namespace:\n%s", err))
   145  							}
   146  							Expect(fw.AsKubeAdmin.HasController.DeleteAllApplicationsInASpecificNamespace(namespace, 30*time.Second)).To(Succeed())
   147  							Expect(fw.AsKubeAdmin.IntegrationController.DeleteAllSnapshotsInASpecificNamespace(namespace, 30*time.Second)).To(Succeed())
   148  							Expect(fw.AsKubeAdmin.TektonController.DeleteAllPipelineRunsInASpecificNamespace(namespace)).To(Succeed())
   149  							Expect(fw.SandboxController.DeleteUserSignup(fw.UserName)).To(BeTrue())
   150  						}
   151  					} else {
   152  						err := fw.AsKubeDeveloper.HasController.DeleteAllApplicationsInASpecificNamespace(fw.UserNamespace, stageTimeout)
   153  						if err != nil {
   154  							GinkgoWriter.Println("Error while deleting resources for user, got error: %v\n", err)
   155  						}
   156  						Expect(err).NotTo(HaveOccurred())
   157  						err = fw.AsKubeDeveloper.HasController.DeleteAllComponentDetectionQueriesInASpecificNamespace(fw.UserNamespace, stageTimeout)
   158  						if err != nil {
   159  							GinkgoWriter.Println("while deleting component detection queries for user, got error: %v\n", err)
   160  						}
   161  						Expect(err).NotTo(HaveOccurred())
   162  					}
   163  				})
   164  
   165  				// Create an application in a specific namespace
   166  				It("creates an application", Label(devEnvTestLabel, stageEnvTestLabel), func() {
   167  					GinkgoWriter.Printf("Parallel process %d\n", GinkgoParallelProcess())
   168  					createdApplication, err := fw.AsKubeDeveloper.HasController.CreateApplication(appTest.ApplicationName, namespace)
   169  					Expect(err).NotTo(HaveOccurred())
   170  					Expect(createdApplication.Spec.DisplayName).To(Equal(appTest.ApplicationName))
   171  					Expect(createdApplication.Namespace).To(Equal(namespace))
   172  				})
   173  
   174  				It("checks if application is healthy", Label(devEnvTestLabel, stageEnvTestLabel), func() {
   175  					Eventually(func() string {
   176  						application, err = fw.AsKubeDeveloper.HasController.GetApplication(appTest.ApplicationName, namespace)
   177  						Expect(err).NotTo(HaveOccurred())
   178  
   179  						return application.Status.Devfile
   180  					}, 3*time.Minute, 100*time.Millisecond).Should(Not(BeEmpty()), fmt.Sprintf("timed out waiting for the %s application in %s namespace to be ready", appTest.ApplicationName, fw.UserNamespace))
   181  				})
   182  
   183  				for _, componentSpec := range appTest.Components {
   184  					componentSpec := componentSpec
   185  					var componentNewBaseBranch string
   186  					componentRepositoryName := utils.ExtractGitRepositoryNameFromURL(componentSpec.GitSourceUrl)
   187  					cdq := &appservice.ComponentDetectionQuery{}
   188  					componentList := []*appservice.Component{}
   189  					var secret string
   190  
   191  					if componentSpec.Private {
   192  						secret = SPIGithubSecretName
   193  						It(fmt.Sprintf("injects manually SPI token for component %s", componentSpec.Name), Label(devEnvTestLabel, stageEnvTestLabel), func() {
   194  							// Inject spi tokens to work with private components
   195  							if componentSpec.ContainerSource != "" {
   196  								// More info about manual token upload for quay.io here: https://github.com/redhat-appstudio/service-provider-integration-operator/pull/115
   197  								oauthCredentials := `{"access_token":"` + utils.GetEnv(constants.QUAY_OAUTH_TOKEN_ENV, "") + `", "username":"` + utils.GetEnv(constants.QUAY_OAUTH_USER_ENV, "") + `"}`
   198  
   199  								_ = fw.AsKubeAdmin.SPIController.InjectManualSPIToken(namespace, componentSpec.ContainerSource, oauthCredentials, corev1.SecretTypeDockerConfigJson, SPIQuaySecretName)
   200  							}
   201  							githubCredentials := `{"access_token":"` + utils.GetEnv(constants.GITHUB_TOKEN_ENV, "") + `"}`
   202  							_ = fw.AsKubeDeveloper.SPIController.InjectManualSPIToken(namespace, componentSpec.GitSourceUrl, githubCredentials, corev1.SecretTypeBasicAuth, SPIGithubSecretName)
   203  						})
   204  					}
   205  
   206  					It(fmt.Sprintf("creates componentdetectionquery for component %s", componentSpec.Name), Label(devEnvTestLabel, stageEnvTestLabel), func() {
   207  						gitRevision := componentSpec.GitSourceRevision
   208  						// In case the advanced build (PaC) is enabled for this component,
   209  						// we need to create a new branch that we will target
   210  						// and that will contain the PaC configuration, so we can avoid polluting the default (main) branch
   211  						if componentSpec.AdvancedBuildSpec != nil {
   212  							componentNewBaseBranch = fmt.Sprintf("base-%s", util.GenerateRandomString(6))
   213  							gitRevision = componentNewBaseBranch
   214  							Expect(fw.AsKubeAdmin.CommonController.Github.CreateRef(componentRepositoryName, componentSpec.GitSourceDefaultBranchName, componentSpec.GitSourceRevision, componentNewBaseBranch)).To(Succeed())
   215  						}
   216  						cdq, err = fw.AsKubeDeveloper.HasController.CreateComponentDetectionQuery(componentSpec.Name, namespace, componentSpec.GitSourceUrl, gitRevision, componentSpec.GitSourceContext, secret, false)
   217  						Expect(err).NotTo(HaveOccurred())
   218  					})
   219  
   220  					It("checks if components have supported languages by AppStudio", Label(devEnvTestLabel, stageEnvTestLabel), func() {
   221  						if appTest.Name == e2eConfig.MultiComponentWithUnsupportedRuntime {
   222  							// Validate that the completed CDQ only has detected 1 component and not also the unsupported component
   223  							Expect(cdq.Status.ComponentDetected).To(HaveLen(1), "cdq also detect unsupported component")
   224  						}
   225  						for _, component := range cdq.Status.ComponentDetected {
   226  							Expect(supportedRuntimes).To(ContainElement(component.ProjectType), "unsupported runtime used for multi component tests")
   227  						}
   228  					})
   229  
   230  					// Components for now can be imported from gitUrl, container image or a devfile
   231  					if componentSpec.GitSourceUrl != "" {
   232  						It(fmt.Sprintf("creates component %s (private: %t) from git source %s", componentSpec.Name, componentSpec.Private, componentSpec.GitSourceUrl), Label(devEnvTestLabel, stageEnvTestLabel), func() {
   233  							for _, compDetected := range cdq.Status.ComponentDetected {
   234  								c, err := fw.AsKubeDeveloper.HasController.CreateComponent(compDetected.ComponentStub, namespace, "", secret, appTest.ApplicationName, true, map[string]string{})
   235  								Expect(err).NotTo(HaveOccurred())
   236  								Expect(c.Name).To(Equal(compDetected.ComponentStub.ComponentName))
   237  								Expect(supportedRuntimes).To(ContainElement(compDetected.ProjectType), "unsupported runtime used for multi component tests")
   238  
   239  								componentList = append(componentList, c)
   240  							}
   241  						})
   242  					} else {
   243  						defer GinkgoRecover()
   244  						Fail("Please Provide a valid test sample")
   245  					}
   246  
   247  					// Start to watch the pipeline until is finished
   248  					It(fmt.Sprintf("waits for %s component (private: %t) pipeline to be finished", componentSpec.Name, componentSpec.Private), Label(devEnvTestLabel, stageEnvTestLabel), func() {
   249  						if componentSpec.ContainerSource != "" {
   250  							Skip(fmt.Sprintf("component %s was imported from quay.io/docker.io source. Skipping pipelinerun check.", componentSpec.Name))
   251  						}
   252  						for _, component := range componentList {
   253  							component, err = fw.AsKubeDeveloper.HasController.GetComponent(component.GetName(), namespace)
   254  							Expect(err).ShouldNot(HaveOccurred(), "failed to get component: %v", err)
   255  
   256  							Expect(fw.AsKubeDeveloper.HasController.WaitForComponentPipelineToBeFinished(component, "",
   257  								fw.AsKubeDeveloper.TektonController, &has.RetryOptions{Retries: 3, Always: true}, nil)).To(Succeed())
   258  						}
   259  					})
   260  
   261  					It("finds the snapshot and checks if it is marked as successful", Label(devEnvTestLabel), func() {
   262  						timeout = time.Second * 600
   263  						interval = time.Second * 10
   264  						for _, component := range componentList {
   265  							Eventually(func() error {
   266  								snapshot, err = fw.AsKubeAdmin.IntegrationController.GetSnapshot("", "", component.Name, namespace)
   267  								if err != nil {
   268  									GinkgoWriter.Println("snapshot has not been found yet")
   269  									return err
   270  								}
   271  								if !fw.AsKubeAdmin.CommonController.HaveTestsSucceeded(snapshot) {
   272  									return fmt.Errorf("tests haven't succeeded for snapshot %s/%s. snapshot status: %+v", snapshot.GetNamespace(), snapshot.GetName(), snapshot.Status)
   273  								}
   274  								return nil
   275  							}, timeout, interval).Should(Succeed(), fmt.Sprintf("timed out waiting for the snapshot for the component %s/%s to be marked as successful", component.GetNamespace(), component.GetName()))
   276  						}
   277  					})
   278  
   279  					if componentSpec.AdvancedBuildSpec != nil {
   280  						Describe(fmt.Sprintf("RHTAP Advanced build test for %s", componentSpec.Name), Label(devEnvTestLabel), Ordered, func() {
   281  							var managedNamespace string
   282  
   283  							var component *appservice.Component
   284  							var release *releaseApi.Release
   285  							var snapshot *appservice.Snapshot
   286  							var pipelineRun, testPipelinerun *tektonapi.PipelineRun
   287  							var integrationTestScenario *integrationv1beta1.IntegrationTestScenario
   288  
   289  							// PaC related variables
   290  							var prNumber int
   291  							var headSHA, pacBranchName, pacPurgeBranchName string
   292  							var mergeResult *github.PullRequestMergeResult
   293  
   294  							BeforeAll(func() {
   295  								if os.Getenv(constants.SKIP_PAC_TESTS_ENV) == "true" {
   296  									Skip("Skipping this test due to configuration issue with Spray proxy")
   297  								}
   298  								managedNamespace = fw.UserNamespace + "-managed"
   299  								component = componentList[0]
   300  
   301  								sharedSecret, err := fw.AsKubeAdmin.CommonController.GetSecret(constants.QuayRepositorySecretNamespace, constants.QuayRepositorySecretName)
   302  								Expect(err).ShouldNot(HaveOccurred(), fmt.Sprintf("error when getting shared secret - make sure the secret %s in %s userNamespace is created", constants.QuayRepositorySecretName, constants.QuayRepositorySecretNamespace))
   303  								createReleaseConfig(*fw, managedNamespace, component.GetName(), appTest.ApplicationName, sharedSecret.Data[".dockerconfigjson"])
   304  
   305  								its := componentSpec.AdvancedBuildSpec.TestScenario
   306  								integrationTestScenario, err = fw.AsKubeAdmin.IntegrationController.CreateIntegrationTestScenario("", appTest.ApplicationName, fw.UserNamespace, its.GitURL, its.GitRevision, its.TestPath)
   307  								Expect(err).ShouldNot(HaveOccurred())
   308  
   309  								pacBranchName = fmt.Sprintf("appstudio-%s", component.GetName())
   310  								pacPurgeBranchName = fmt.Sprintf("appstudio-purge-%s", component.GetName())
   311  
   312  								// JBS related config
   313  								_, err = fw.AsKubeAdmin.JvmbuildserviceController.CreateJBSConfig(constants.JBSConfigName, fw.UserNamespace)
   314  								Expect(err).ShouldNot(HaveOccurred())
   315  								Expect(fw.AsKubeAdmin.JvmbuildserviceController.WaitForCache(fw.AsKubeAdmin.CommonController, fw.UserNamespace)).Should(Succeed())
   316  							})
   317  							AfterAll(func() {
   318  								if !CurrentSpecReport().Failed() {
   319  									Expect(fw.AsKubeAdmin.CommonController.DeleteNamespace(managedNamespace)).To(Succeed())
   320  									Expect(fw.AsKubeAdmin.JvmbuildserviceController.DeleteJBSConfig(constants.JBSConfigName, fw.UserNamespace)).To(Succeed())
   321  								}
   322  
   323  								// Delete new branch created by PaC and a testing branch used as a component's base branch
   324  								err = fw.AsKubeAdmin.CommonController.Github.DeleteRef(componentRepositoryName, pacBranchName)
   325  								if err != nil {
   326  									Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   327  								}
   328  								Expect(fw.AsKubeAdmin.CommonController.Github.DeleteRef(componentRepositoryName, componentNewBaseBranch)).To(Succeed())
   329  							})
   330  							When("Component is switched to Advanced Build mode", func() {
   331  
   332  								BeforeAll(func() {
   333  									component, err = fw.AsKubeAdmin.HasController.GetComponent(component.GetName(), fw.UserNamespace)
   334  									Expect(err).ShouldNot(HaveOccurred(), "failed to get component: %v", err)
   335  
   336  									component.Annotations["skip-initial-checks"] = "false"
   337  									for k, v := range constants.ComponentPaCRequestAnnotation {
   338  										component.Annotations[k] = v
   339  									}
   340  									Expect(fw.AsKubeAdmin.CommonController.KubeRest().Update(context.Background(), component)).To(Succeed())
   341  									Expect(err).ShouldNot(HaveOccurred(), "failed to update component: %v", err)
   342  								})
   343  
   344  								It("triggers creation of a PR in the sample repo", func() {
   345  
   346  									var prSHA string
   347  									Eventually(func() error {
   348  										prs, err := fw.AsKubeAdmin.CommonController.Github.ListPullRequests(componentRepositoryName)
   349  										Expect(err).ShouldNot(HaveOccurred())
   350  										for _, pr := range prs {
   351  											if pr.Head.GetRef() == pacBranchName {
   352  												prNumber = pr.GetNumber()
   353  												prSHA = pr.GetHead().GetSHA()
   354  												return nil
   355  											}
   356  										}
   357  										return fmt.Errorf("could not get the expected PaC branch name %s", pacBranchName)
   358  									}, pullRequestCreationTimeout, defaultPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for init PaC PR (branch %q) to be created against the %q repo", pacBranchName, componentRepositoryName))
   359  
   360  									// We actually don't need the "on-pull-request" PipelineRun to complete, so we can delete it
   361  									Eventually(func() error {
   362  										pipelineRun, err = fw.AsKubeAdmin.HasController.GetComponentPipelineRun(component.GetName(), appTest.ApplicationName, fw.UserNamespace, prSHA)
   363  										if err == nil {
   364  											Expect(fw.AsKubeAdmin.TektonController.DeletePipelineRun(pipelineRun.Name, pipelineRun.Namespace)).To(Succeed())
   365  											return nil
   366  										}
   367  										return err
   368  									}, pipelineRunStartedTimeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for init PaC PipelineRun to be present in the user namespace %q for component %q with a label pointing to %q", fw.UserNamespace, component.GetName(), appTest.ApplicationName))
   369  
   370  								})
   371  
   372  								It("component build status is set correctly", func() {
   373  									var buildStatus *buildcontrollers.BuildStatus
   374  									Eventually(func() (bool, error) {
   375  										component, err := fw.AsKubeAdmin.HasController.GetComponent(component.GetName(), fw.UserNamespace)
   376  										if err != nil {
   377  											return false, err
   378  										}
   379  
   380  										statusBytes := []byte(component.Annotations[buildcontrollers.BuildStatusAnnotationName])
   381  
   382  										err = json.Unmarshal(statusBytes, &buildStatus)
   383  										if err != nil {
   384  											return false, err
   385  										}
   386  
   387  										if buildStatus.PaC != nil {
   388  											GinkgoWriter.Printf("state: %s\n", buildStatus.PaC.State)
   389  											GinkgoWriter.Printf("mergeUrl: %s\n", buildStatus.PaC.MergeUrl)
   390  											GinkgoWriter.Printf("errId: %d\n", buildStatus.PaC.ErrId)
   391  											GinkgoWriter.Printf("errMessage: %s\n", buildStatus.PaC.ErrMessage)
   392  											GinkgoWriter.Printf("configurationTime: %s\n", buildStatus.PaC.ConfigurationTime)
   393  										} else {
   394  											GinkgoWriter.Println("build status does not have PaC field")
   395  										}
   396  
   397  										return buildStatus.PaC != nil && buildStatus.PaC.State == "enabled" && buildStatus.PaC.MergeUrl != "" && buildStatus.PaC.ErrId == 0 && buildStatus.PaC.ConfigurationTime != "", nil
   398  									}, timeout, interval).Should(BeTrue(), "component build status has unexpected content")
   399  								})
   400  								It("should eventually lead to triggering another PipelineRun after merging the PaC init branch ", func() {
   401  									Eventually(func() error {
   402  										mergeResult, err = fw.AsKubeAdmin.CommonController.Github.MergePullRequest(componentRepositoryName, prNumber)
   403  										return err
   404  									}, mergePRTimeout).Should(BeNil(), fmt.Sprintf("error when merging PaC pull request: %+v\n", err))
   405  
   406  									headSHA = mergeResult.GetSHA()
   407  
   408  									Eventually(func() error {
   409  										pipelineRun, err = fw.AsKubeAdmin.HasController.GetComponentPipelineRun(component.GetName(), appTest.ApplicationName, fw.UserNamespace, headSHA)
   410  										if err != nil {
   411  											GinkgoWriter.Printf("PipelineRun has not been created yet for component %s/%s\n", fw.UserNamespace, component.GetName())
   412  											return err
   413  										}
   414  										if !pipelineRun.HasStarted() {
   415  											return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pipelineRun.GetNamespace(), pipelineRun.GetName())
   416  										}
   417  										return nil
   418  									}, pipelineRunStartedTimeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for a PipelineRun in namespace %q with label component label %q and application label %q and sha label %q to start", fw.UserNamespace, component.GetName(), appTest.ApplicationName, headSHA))
   419  								})
   420  							})
   421  
   422  							When("SLSA level 3 customizable PipelineRun is created", func() {
   423  								It("does not contain an annotation with a Snapshot Name", func() {
   424  									Expect(pipelineRun.Annotations["appstudio.openshift.io/snapshot"]).To(Equal(""))
   425  								})
   426  								It("should eventually complete successfully", func() {
   427  									Expect(fw.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component, headSHA,
   428  										fw.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 5, Always: true}, pipelineRun)).To(Succeed())
   429  
   430  									// in case the first pipelineRun attempt has failed and was retried, we need to update the git branch head ref
   431  									headSHA = pipelineRun.Labels["pipelinesascode.tekton.dev/sha"]
   432  								})
   433  							})
   434  
   435  							When("SLSA level 3 customizable PipelineRun completes successfully", func() {
   436  								It("should be possible to download the SBOM file", func() {
   437  									var outputImage string
   438  									for _, p := range pipelineRun.Spec.Params {
   439  										if p.Name == "output-image" {
   440  											outputImage = p.Value.StringVal
   441  										}
   442  									}
   443  									Expect(outputImage).ToNot(BeEmpty(), "output image of a component could not be found")
   444  
   445  									_, _, err = build.GetParsedSbomFilesContentFromImage(outputImage)
   446  									Expect(err).NotTo(HaveOccurred())
   447  								})
   448  
   449  								It("should validate Tekton TaskRun test results successfully", func() {
   450  									pipelineRun, err = fw.AsKubeAdmin.HasController.GetComponentPipelineRun(component.GetName(), appTest.ApplicationName, fw.UserNamespace, headSHA)
   451  									Expect(err).ShouldNot(HaveOccurred())
   452  									Expect(build.ValidateBuildPipelineTestResults(pipelineRun, fw.AsKubeAdmin.CommonController.KubeRest())).To(Succeed())
   453  								})
   454  
   455  								It("should validate pipelineRun is signed", func() {
   456  									pipelineRun, err = fw.AsKubeAdmin.HasController.GetComponentPipelineRun(component.GetName(), appTest.ApplicationName, fw.UserNamespace, headSHA)
   457  									Expect(err).ShouldNot(HaveOccurred())
   458  									Expect(pipelineRun.Annotations["chains.tekton.dev/signed"]).To(Equal("true"), fmt.Sprintf("pipelinerun %s/%s does not have the expected value of annotation 'chains.tekton.dev/signed'", pipelineRun.GetNamespace(), pipelineRun.GetName()))
   459  								})
   460  
   461  								It("should find the related Snapshot CR", func() {
   462  									Eventually(func() error {
   463  										snapshot, err = fw.AsKubeAdmin.IntegrationController.GetSnapshot("", pipelineRun.Name, "", fw.UserNamespace)
   464  										return err
   465  									}, snapshotTimeout, snapshotPollingInterval).Should(Succeed(), "timed out when trying to check if the Snapshot exists for PipelineRun %s/%s", fw.UserNamespace, pipelineRun.GetName())
   466  								})
   467  
   468  								It("should validate the pipelineRun is annotated with the name of the Snapshot", func() {
   469  									pipelineRun, err = fw.AsKubeAdmin.HasController.GetComponentPipelineRun(component.GetName(), appTest.ApplicationName, fw.UserNamespace, headSHA)
   470  									Expect(err).ShouldNot(HaveOccurred())
   471  									Expect(pipelineRun.Annotations["appstudio.openshift.io/snapshot"]).To(Equal(snapshot.GetName()))
   472  								})
   473  
   474  								It("should find the related Integration Test PipelineRun", func() {
   475  									Eventually(func() error {
   476  										testPipelinerun, err = fw.AsKubeAdmin.IntegrationController.GetIntegrationPipelineRun(integrationTestScenario.Name, snapshot.Name, fw.UserNamespace)
   477  										if err != nil {
   478  											GinkgoWriter.Printf("failed to get Integration test PipelineRun for a snapshot '%s' in '%s' namespace: %+v\n", snapshot.Name, fw.UserNamespace, err)
   479  											return err
   480  										}
   481  										if !testPipelinerun.HasStarted() {
   482  											return fmt.Errorf("pipelinerun %s/%s hasn't started yet", testPipelinerun.GetNamespace(), testPipelinerun.GetName())
   483  										}
   484  										return nil
   485  									}, pipelineRunStartedTimeout, defaultPollingInterval).Should(Succeed())
   486  									Expect(testPipelinerun.Labels["appstudio.openshift.io/snapshot"]).To(ContainSubstring(snapshot.Name))
   487  									Expect(testPipelinerun.Labels["test.appstudio.openshift.io/scenario"]).To(ContainSubstring(integrationTestScenario.Name))
   488  								})
   489  							})
   490  
   491  							When("Integration Test PipelineRun is created", func() {
   492  								It("should eventually complete successfully", func() {
   493  									Expect(fw.AsKubeAdmin.IntegrationController.WaitForIntegrationPipelineToBeFinished(integrationTestScenario, snapshot, fw.UserNamespace)).To(Succeed(), fmt.Sprintf("Error when waiting for a integration pipeline for snapshot %s/%s to finish", fw.UserNamespace, snapshot.GetName()))
   494  								})
   495  							})
   496  
   497  							When("Integration Test PipelineRun completes successfully", func() {
   498  
   499  								It("should lead to Snapshot CR being marked as passed", func() {
   500  									snapshot, err = fw.AsKubeAdmin.IntegrationController.GetSnapshot("", pipelineRun.Name, "", fw.UserNamespace)
   501  									Expect(err).ShouldNot(HaveOccurred())
   502  									Eventually(func() bool {
   503  										return fw.AsKubeAdmin.CommonController.HaveTestsSucceeded(snapshot)
   504  									}, time.Minute*5, defaultPollingInterval).Should(BeTrue(), fmt.Sprintf("tests have not succeeded for snapshot %s/%s", snapshot.GetNamespace(), snapshot.GetName()))
   505  								})
   506  
   507  								It("should trigger creation of Release CR", func() {
   508  									Eventually(func() error {
   509  										release, err = fw.AsKubeAdmin.ReleaseController.GetRelease("", snapshot.Name, fw.UserNamespace)
   510  										return err
   511  									}, releaseTimeout, releasePollingInterval).Should(Succeed(), fmt.Sprintf("timed out when trying to check if the release exists for snapshot %s/%s", fw.UserNamespace, snapshot.GetName()))
   512  								})
   513  							})
   514  
   515  							When("Release CR is created", func() {
   516  								It("triggers creation of Release PipelineRun", func() {
   517  									Eventually(func() error {
   518  										pipelineRun, err = fw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedNamespace, release.Name, release.Namespace)
   519  										if err != nil {
   520  											GinkgoWriter.Printf("pipelineRun for component '%s' in namespace '%s' not created yet: %+v\n", component.GetName(), managedNamespace, err)
   521  											return err
   522  										}
   523  										if !pipelineRun.HasStarted() {
   524  											return fmt.Errorf("pipelinerun %s/%s hasn't started yet", pipelineRun.GetNamespace(), pipelineRun.GetName())
   525  										}
   526  										return nil
   527  									}, pipelineRunStartedTimeout, defaultPollingInterval).Should(Succeed(), fmt.Sprintf("failed to get pipelinerun named %q in namespace %q with label to release %q in namespace %q to start", pipelineRun.Name, managedNamespace, release.Name, release.Namespace))
   528  								})
   529  							})
   530  
   531  							When("Release PipelineRun is triggered", func() {
   532  								It("should eventually succeed", func() {
   533  									Eventually(func() error {
   534  										pr, err := fw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedNamespace, release.Name, release.Namespace)
   535  										Expect(err).ShouldNot(HaveOccurred())
   536  										Expect(tekton.HasPipelineRunFailed(pr)).NotTo(BeTrue(), fmt.Sprintf("did not expect PipelineRun %s/%s to fail", pr.GetNamespace(), pr.GetName()))
   537  										if !pr.IsDone() {
   538  											return fmt.Errorf("release pipelinerun %s/%s has not finished yet", pr.GetNamespace(), pr.GetName())
   539  										}
   540  										Expect(tekton.HasPipelineRunSucceeded(pr)).To(BeTrue(), fmt.Sprintf("PipelineRun %s/%s did not succeed", pr.GetNamespace(), pr.GetName()))
   541  										return nil
   542  									}, releasePipelineTimeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("failed to see pipelinerun %q in namespace %q with a label pointing to release %q in namespace %q to complete successfully", pipelineRun.Name, managedNamespace, release.Name, release.Namespace))
   543  								})
   544  							})
   545  							When("Release PipelineRun is completed", func() {
   546  								It("should lead to Release CR being marked as succeeded", func() {
   547  									Eventually(func() error {
   548  										release, err = fw.AsKubeAdmin.ReleaseController.GetRelease(release.Name, "", fw.UserNamespace)
   549  										Expect(err).ShouldNot(HaveOccurred())
   550  										if !release.IsReleased() {
   551  											return fmt.Errorf("release CR %s/%s is not marked as finished yet", release.GetNamespace(), release.GetName())
   552  										}
   553  										return nil
   554  									}, customResourceUpdateTimeout, defaultPollingInterval).Should(Succeed(), fmt.Sprintf("failed to see release %q in namespace %q get marked as released", release.Name, fw.UserNamespace))
   555  								})
   556  							})
   557  
   558  							When("JVM Build Service is used for rebuilding dependencies", func() {
   559  								It("should eventually rebuild of all artifacts and dependencies successfully", func() {
   560  									jvmClient := jvmclientSet.New(fw.AsKubeAdmin.JvmbuildserviceController.JvmbuildserviceClient().JvmbuildserviceV1alpha1().RESTClient())
   561  									tektonClient := pipelineclientset.New(fw.AsKubeAdmin.TektonController.PipelineClient().TektonV1beta1().RESTClient())
   562  									kubeClient := kubernetes.New(fw.AsKubeAdmin.CommonController.KubeInterface().CoreV1().RESTClient())
   563  									//status report ends up in artifacts/redhat-appstudio-e2e/redhat-appstudio-e2e/artifacts/rp_preproc/attachments/xunit
   564  									defer e2e.GenerateStatusReport(fw.UserNamespace, jvmClient, kubeClient, tektonClient)
   565  									Eventually(func() error {
   566  										abList, err := fw.AsKubeAdmin.JvmbuildserviceController.ListArtifactBuilds(fw.UserNamespace)
   567  										Expect(err).ShouldNot(HaveOccurred())
   568  										for _, ab := range abList.Items {
   569  											if ab.Status.State != v1alpha1.ArtifactBuildStateComplete {
   570  												return fmt.Errorf("artifactbuild %s not complete", ab.Spec.GAV)
   571  											}
   572  										}
   573  										dbList, err := fw.AsKubeAdmin.JvmbuildserviceController.ListDependencyBuilds(fw.UserNamespace)
   574  										Expect(err).ShouldNot(HaveOccurred())
   575  										for _, db := range dbList.Items {
   576  											if db.Status.State != v1alpha1.DependencyBuildStateComplete {
   577  												return fmt.Errorf("dependencybuild %s not complete", db.Spec.ScmInfo.SCMURL)
   578  											}
   579  										}
   580  										return nil
   581  									}, jvmRebuildTimeout, jvmRebuildPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for all artifactbuilds and dependencybuilds to complete in namespace %q", fw.UserNamespace))
   582  								})
   583  							})
   584  
   585  							When("User switches to simple build", func() {
   586  								BeforeAll(func() {
   587  									Expect(fw.AsKubeAdmin.HasController.SetComponentAnnotation(component.GetName(), buildcontrollers.BuildRequestAnnotationName, buildcontrollers.BuildRequestUnconfigurePaCAnnotationValue, fw.UserNamespace)).To(Succeed())
   588  								})
   589  								AfterAll(func() {
   590  									// Delete the new branch created by sending purge PR while moving to simple build
   591  									err = fw.AsKubeAdmin.CommonController.Github.DeleteRef(componentRepositoryName, pacPurgeBranchName)
   592  									if err != nil {
   593  										Expect(err.Error()).To(ContainSubstring("Reference does not exist"))
   594  									}
   595  								})
   596  								It("creates a pull request for removing PAC configuration", func() {
   597  									Eventually(func() error {
   598  										prs, err := fw.AsKubeAdmin.CommonController.Github.ListPullRequests(componentRepositoryName)
   599  										Expect(err).ShouldNot(HaveOccurred())
   600  										for _, pr := range prs {
   601  											if pr.Head.GetRef() == pacPurgeBranchName {
   602  												return nil
   603  											}
   604  										}
   605  										return fmt.Errorf("could not get the expected PaC purge PR branch %s", pacPurgeBranchName)
   606  									}, time.Minute*1, defaultPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for PaC purge PR to be created against the %q repo", componentRepositoryName))
   607  								})
   608  								It("component status annotation is set correctly", func() {
   609  									var buildStatus *buildcontrollers.BuildStatus
   610  
   611  									Eventually(func() (bool, error) {
   612  										component, err := fw.AsKubeAdmin.HasController.GetComponent(component.GetName(), fw.UserNamespace)
   613  										status := component.Annotations[buildcontrollers.BuildStatusAnnotationName]
   614  
   615  										if err != nil {
   616  											GinkgoWriter.Printf("cannot get the build status annotation: %v\n", err)
   617  											return false, err
   618  										}
   619  
   620  										statusBytes := []byte(status)
   621  
   622  										err = json.Unmarshal(statusBytes, &buildStatus)
   623  										if err != nil {
   624  											GinkgoWriter.Printf("cannot unmarshal build status: %v\n", err)
   625  											return false, err
   626  										}
   627  
   628  										return buildStatus.PaC.State != "enabled", nil
   629  									}, timeout, interval).Should(BeTrue(), "PaC is still enabled, even after unprovisioning")
   630  								})
   631  							})
   632  						})
   633  					}
   634  				}
   635  			})
   636  		}
   637  	}
   638  })
   639  
   640  func createReleaseConfig(fw framework.Framework, managedNamespace, componentName, appName string, secretData []byte) {
   641  	var err error
   642  	_, err = fw.AsKubeAdmin.CommonController.CreateTestNamespace(managedNamespace)
   643  	Expect(err).ShouldNot(HaveOccurred())
   644  
   645  	secret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "release-pull-secret", Namespace: managedNamespace},
   646  		Data: map[string][]byte{".dockerconfigjson": secretData},
   647  		Type: corev1.SecretTypeDockerConfigJson,
   648  	}
   649  	_, err = fw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, secret)
   650  	Expect(err).ShouldNot(HaveOccurred())
   651  
   652  	managedServiceAccount, err := fw.AsKubeAdmin.CommonController.CreateServiceAccount("release-service-account", managedNamespace, []corev1.ObjectReference{{Name: secret.Name}}, nil)
   653  	Expect(err).NotTo(HaveOccurred())
   654  
   655  	_, err = fw.AsKubeAdmin.ReleaseController.CreateReleasePipelineRoleBindingForServiceAccount(fw.UserNamespace, managedServiceAccount)
   656  	Expect(err).NotTo(HaveOccurred())
   657  	_, err = fw.AsKubeAdmin.ReleaseController.CreateReleasePipelineRoleBindingForServiceAccount(managedNamespace, managedServiceAccount)
   658  	Expect(err).NotTo(HaveOccurred())
   659  
   660  	publicKey, err := fw.AsKubeAdmin.TektonController.GetTektonChainsPublicKey()
   661  	Expect(err).ToNot(HaveOccurred())
   662  
   663  	Expect(fw.AsKubeAdmin.TektonController.CreateOrUpdateSigningSecret(publicKey, "cosign-public-key", managedNamespace)).To(Succeed())
   664  
   665  	_, err = fw.AsKubeAdmin.ReleaseController.CreateReleasePlan("source-releaseplan", fw.UserNamespace, appName, managedNamespace, "", nil)
   666  	Expect(err).NotTo(HaveOccurred())
   667  
   668  	defaultEcPolicy, err := fw.AsKubeAdmin.TektonController.GetEnterpriseContractPolicy("default", "enterprise-contract-service")
   669  	Expect(err).NotTo(HaveOccurred())
   670  	ecPolicyName := componentName + "-policy"
   671  	defaultEcPolicySpec := ecp.EnterpriseContractPolicySpec{
   672  		Description: "Red Hat's enterprise requirements",
   673  		PublicKey:   string(publicKey),
   674  		Sources:     defaultEcPolicy.Spec.Sources,
   675  		Configuration: &ecp.EnterpriseContractPolicyConfiguration{
   676  			Collections: []string{"minimal"},
   677  			Exclude:     []string{"cve"},
   678  		},
   679  	}
   680  	_, err = fw.AsKubeAdmin.TektonController.CreateEnterpriseContractPolicy(ecPolicyName, managedNamespace, defaultEcPolicySpec)
   681  	Expect(err).NotTo(HaveOccurred())
   682  
   683  	_, err = fw.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission("demo", managedNamespace, "", fw.UserNamespace, ecPolicyName, "release-service-account", []string{appName}, true, &tektonutils.PipelineRef{
   684  		Resolver: "git",
   685  		Params: []tektonutils.Param{
   686  			{Name: "url", Value: releasecommon.RelSvcCatalogURL},
   687  			{Name: "revision", Value: releasecommon.RelSvcCatalogRevision},
   688  			{Name: "pathInRepo", Value: "pipelines/e2e/e2e.yaml"},
   689  		},
   690  	}, nil)
   691  	Expect(err).NotTo(HaveOccurred())
   692  
   693  	_, err = fw.AsKubeAdmin.TektonController.CreatePVCInAccessMode("release-pvc", managedNamespace, corev1.ReadWriteOnce)
   694  	Expect(err).NotTo(HaveOccurred())
   695  
   696  	_, err = fw.AsKubeAdmin.CommonController.CreateRole("role-release-service-account", managedNamespace, map[string][]string{
   697  		"apiGroupsList": {""},
   698  		"roleResources": {"secrets"},
   699  		"roleVerbs":     {"get", "list", "watch"},
   700  	})
   701  	Expect(err).NotTo(HaveOccurred())
   702  
   703  	_, err = fw.AsKubeAdmin.CommonController.CreateRoleBinding("role-release-service-account-binding", managedNamespace, "ServiceAccount", "release-service-account", managedNamespace, "Role", "role-release-service-account", "rbac.authorization.k8s.io")
   704  	Expect(err).NotTo(HaveOccurred())
   705  }