github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/tests/integration-service/gitlab-integration-reporting.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/devfile/library/v2/pkg/util"
    11  	"github.com/redhat-appstudio/e2e-tests/pkg/clients/has"
    12  	"github.com/redhat-appstudio/e2e-tests/pkg/constants"
    13  	"github.com/redhat-appstudio/e2e-tests/pkg/framework"
    14  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    15  
    16  	v1 "k8s.io/api/core/v1"
    17  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    18  
    19  	integrationv1beta1 "github.com/konflux-ci/integration-service/api/v1beta1"
    20  	. "github.com/onsi/ginkgo/v2"
    21  	. "github.com/onsi/gomega"
    22  	appstudioApi "github.com/redhat-appstudio/application-api/api/v1alpha1"
    23  	pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
    24  )
    25  
    26  var _ = framework.IntegrationServiceSuiteDescribe("Gitlab Status Reporting of Integration tests", Label("integration-service", "HACBS", "gitlab-status-reporting"), func() {
    27  	defer GinkgoRecover()
    28  
    29  	var f *framework.Framework
    30  	var err error
    31  
    32  	var mrID int
    33  	// var mrNote *gitlab.Note
    34  	var timeout, interval time.Duration
    35  	var mrSha, projectID, gitlabToken string
    36  	var snapshot *appstudioApi.Snapshot
    37  	var component *appstudioApi.Component
    38  	var buildPipelineRun, testPipelinerun *pipeline.PipelineRun
    39  	var integrationTestScenarioPass, integrationTestScenarioFail *integrationv1beta1.IntegrationTestScenario
    40  	var applicationName, componentName, componentBaseBranchName, pacBranchName, testNamespace string
    41  
    42  	AfterEach(framework.ReportFailure(&f))
    43  
    44  	Describe("Gitlab with status reporting of Integration tests in the assosiated merge request", Ordered, func() {
    45  		BeforeAll(func() {
    46  			if os.Getenv(constants.SKIP_PAC_TESTS_ENV) == "true" {
    47  				Skip("Skipping this test due to configuration issue with Spray proxy")
    48  			}
    49  
    50  			f, err = framework.NewFramework(utils.GetGeneratedNamespace("gitlab-rep"))
    51  			Expect(err).NotTo(HaveOccurred())
    52  			testNamespace = f.UserNamespace
    53  
    54  			if utils.IsPrivateHostname(f.OpenshiftConsoleHost) {
    55  				Skip("Using private cluster (not reachable from Github), skipping...")
    56  			}
    57  
    58  			applicationName = createApp(*f, testNamespace)
    59  
    60  			integrationTestScenarioPass, err = f.AsKubeAdmin.IntegrationController.CreateIntegrationTestScenario("", applicationName, testNamespace, gitURL, revision, pathInRepoPass)
    61  			Expect(err).ShouldNot(HaveOccurred())
    62  
    63  			integrationTestScenarioFail, err = f.AsKubeAdmin.IntegrationController.CreateIntegrationTestScenario("", applicationName, testNamespace, gitURL, revision, pathInRepoFail)
    64  			Expect(err).ShouldNot(HaveOccurred())
    65  
    66  			componentName = fmt.Sprintf("%s-%s", "test-comp-pac-gitlab", util.GenerateRandomString(6))
    67  			pacBranchName = constants.PaCPullRequestBranchPrefix + componentName
    68  			componentBaseBranchName = fmt.Sprintf("base-gitlab-%s", util.GenerateRandomString(6))
    69  
    70  			projectID = utils.GetEnv(constants.GITLAB_PROJECT_ID, "")
    71  			Expect(projectID).ShouldNot(BeEmpty())
    72  
    73  			gitlabToken = utils.GetEnv(constants.GITLAB_TOKEN_ENV, "")
    74  			Expect(gitlabToken).ShouldNot(BeEmpty())
    75  
    76  			err = f.AsKubeAdmin.CommonController.Gitlab.CreateGitlabNewBranch(projectID, componentBaseBranchName, componentRevision, componentDefaultBranch)
    77  			Expect(err).ShouldNot(HaveOccurred())
    78  
    79  			secretAnnotations := map[string]string{}
    80  
    81  			err = createBuildSecret(f, "gitlab-build-secret", secretAnnotations, gitlabToken)
    82  			Expect(err).ShouldNot(HaveOccurred())
    83  
    84  			secret := &v1.Secret{
    85  				ObjectMeta: metav1.ObjectMeta{
    86  					Name:      "pipelines-as-code-secret",
    87  					Namespace: testNamespace,
    88  				},
    89  				Type: v1.SecretTypeOpaque,
    90  				StringData: map[string]string{
    91  					"password": gitlabToken,
    92  				},
    93  			}
    94  
    95  			// create a pipeline-as-code-secret in testNamespace
    96  			_, err = f.AsKubeAdmin.CommonController.CreateSecret(f.UserNamespace, secret)
    97  			Expect(err).NotTo(HaveOccurred())
    98  		})
    99  
   100  		AfterAll(func() {
   101  			if !CurrentSpecReport().Failed() {
   102  				// Cleanup test, close MR if opned delete created brnach , delete usersignup  and namespace.
   103  				Expect(f.AsKubeAdmin.CommonController.Gitlab.CloseMergeRequest(projectID, mrID)).NotTo(HaveOccurred())
   104  				Expect(f.AsKubeAdmin.CommonController.Gitlab.DeleteBranch(projectID, componentBaseBranchName)).NotTo(HaveOccurred())
   105  				Expect(f.SandboxController.DeleteUserSignup(f.UserName)).To(BeTrue())
   106  
   107  			}
   108  
   109  		})
   110  
   111  		When("a new Component with specified custom branch is created", Label("custom-branch"), func() {
   112  			BeforeAll(func() {
   113  				componentObj := appstudioApi.ComponentSpec{
   114  					ComponentName: componentName,
   115  					Application:   applicationName,
   116  					Source: appstudioApi.ComponentSource{
   117  						ComponentSourceUnion: appstudioApi.ComponentSourceUnion{
   118  							GitSource: &appstudioApi.GitSource{
   119  								URL:        gitlabComponentGitSourceURLForStatusReporting,
   120  								Revision:   componentBaseBranchName,
   121  								DevfileURL: gitlabComponentSourceForGitlabReportingDevFile,
   122  							},
   123  						},
   124  					},
   125  				}
   126  				// Create a component with Git Source URL, a specified git branch
   127  				component, err = f.AsKubeAdmin.HasController.CreateComponent(componentObj, testNamespace, "", "", applicationName, false, utils.MergeMaps(constants.ComponentPaCRequestAnnotation, constants.ImageControllerAnnotationRequestPublicRepo))
   128  				Expect(err).ShouldNot(HaveOccurred())
   129  			})
   130  
   131  			It("triggers a Build PipelineRun", func() {
   132  				timeout = time.Second * 600
   133  				interval = time.Second * 1
   134  				Eventually(func() error {
   135  					buildPipelineRun, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, "")
   136  					if err != nil {
   137  						GinkgoWriter.Printf("Build PipelineRun has not been created yet for the component %s/%s\n", testNamespace, componentName)
   138  						return err
   139  					}
   140  					if !buildPipelineRun.HasStarted() {
   141  						return fmt.Errorf("build pipelinerun %s/%s hasn't started yet", buildPipelineRun.GetNamespace(), buildPipelineRun.GetName())
   142  					}
   143  					return nil
   144  				}, timeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the build PipelineRun to start for the component %s/%s", testNamespace, componentName))
   145  			})
   146  
   147  			It("does not contain an annotation with a Snapshot Name", func() {
   148  				Expect(buildPipelineRun.Annotations[snapshotAnnotation]).To(Equal(""))
   149  			})
   150  
   151  			It("should lead to build PipelineRun finishing successfully", func() {
   152  				Expect(f.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component,
   153  					"", f.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 2, Always: true}, buildPipelineRun)).To(Succeed())
   154  			})
   155  
   156  			It("should have a related PaC init MR is created", func() {
   157  				timeout = time.Second * 300
   158  				interval = time.Second * 1
   159  
   160  				Eventually(func() bool {
   161  					mrs, err := f.AsKubeAdmin.CommonController.Gitlab.GetMergeRequests()
   162  					Expect(err).ShouldNot(HaveOccurred())
   163  
   164  					for _, mr := range mrs {
   165  						if mr.SourceBranch == pacBranchName {
   166  							mrID = mr.IID
   167  							mrSha = mr.SHA
   168  							return true
   169  						}
   170  					}
   171  					return false
   172  				}, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out when waiting for init PaC MR (branch name '%s') to be created in %s repository", pacBranchName, componentRepoNameForStatusReporting))
   173  
   174  				// in case the first pipelineRun attempt has failed and was retried, we need to update the value of pipelineRun variable
   175  				buildPipelineRun, err = f.AsKubeAdmin.HasController.GetComponentPipelineRun(componentName, applicationName, testNamespace, mrSha)
   176  				Expect(err).ShouldNot(HaveOccurred())
   177  			})
   178  
   179  			It("eventually leads to the build PipelineRun's status reported at MR notes", func() {
   180  				expectedNote := fmt.Sprintf("**Pipelines as Code CI/%s-on-pull-request** has successfully validated your commit", componentName)
   181  				validateNoteInMergeRequestComment(f, projectID, expectedNote, mrID)
   182  			})
   183  		})
   184  
   185  		When("the PaC build pipelineRun run succeeded", func() {
   186  			It("checks if the BuildPipelineRun have the annotation of chains signed", func() {
   187  				Expect(f.AsKubeDeveloper.IntegrationController.WaitForBuildPipelineRunToGetAnnotated(testNamespace, applicationName, componentName, chainsSignedAnnotation)).To(Succeed())
   188  			})
   189  
   190  			It("checks if the Snapshot is created", func() {
   191  				snapshot, err = f.AsKubeDeveloper.IntegrationController.WaitForSnapshotToGetCreated("", "", componentName, testNamespace)
   192  				Expect(err).ToNot(HaveOccurred())
   193  			})
   194  
   195  			It("checks if the Build PipelineRun got annotated with Snapshot name", func() {
   196  				Expect(f.AsKubeDeveloper.IntegrationController.WaitForBuildPipelineRunToGetAnnotated(testNamespace, applicationName, componentName, snapshotAnnotation)).To(Succeed())
   197  			})
   198  		})
   199  
   200  		When("the Snapshot was created", func() {
   201  			It("should find the Integration Test Scenario PipelineRun", func() {
   202  				testPipelinerun, err = f.AsKubeDeveloper.IntegrationController.WaitForIntegrationPipelineToGetStarted(integrationTestScenarioPass.Name, snapshot.Name, testNamespace)
   203  				Expect(err).ToNot(HaveOccurred())
   204  				Expect(testPipelinerun.Labels[snapshotAnnotation]).To(ContainSubstring(snapshot.Name))
   205  				Expect(testPipelinerun.Labels[scenarioAnnotation]).To(ContainSubstring(integrationTestScenarioPass.Name))
   206  
   207  				Expect(testPipelinerun.Labels[snapshotAnnotation]).To(ContainSubstring(snapshot.Name))
   208  
   209  			})
   210  		})
   211  
   212  		When("Integration PipelineRun is created", func() {
   213  			It("should eventually complete successfully", func() {
   214  				Expect(f.AsKubeAdmin.IntegrationController.WaitForIntegrationPipelineToBeFinished(integrationTestScenarioPass, snapshot, testNamespace)).To(Succeed(), fmt.Sprintf("Error when waiting for an integration pipelinerun for snapshot %s/%s to finish", testNamespace, snapshot.GetName()))
   215  				Expect(f.AsKubeAdmin.IntegrationController.WaitForIntegrationPipelineToBeFinished(integrationTestScenarioFail, snapshot, testNamespace)).To(Succeed(), fmt.Sprintf("Error when waiting for an integration pipelinerun for snapshot %s/%s to finish", testNamespace, snapshot.GetName()))
   216  			})
   217  
   218  			It("validates the Integration test scenario PipelineRun is reported to merge request CommitStatus, and it pass", func() {
   219  				timeout = time.Second * 300
   220  				interval = time.Second * 1
   221  
   222  				Eventually(func() string {
   223  					commitStatuses, _, err := f.AsKubeAdmin.CommonController.Gitlab.GetClient().Commits.GetCommitStatuses(projectID, mrSha, nil)
   224  					Expect(err).ShouldNot(HaveOccurred())
   225  
   226  					for _, commitStatus := range commitStatuses {
   227  						commitStatusNames := strings.Split(commitStatus.Name, "/")
   228  						if len(commitStatusNames) > 2 {
   229  							if strings.Contains(integrationTestScenarioPass.Name, strings.TrimSpace(commitStatusNames[1])) {
   230  								return commitStatus.Status
   231  							}
   232  						}
   233  					}
   234  					return ""
   235  				}, timeout, interval).Should(Equal(integrationPipelineRunCommitStatusSuccess), fmt.Sprintf("timed out when waiting for expected commitStatus to be created for sha %s in %s repository", mrSha, componentRepoNameForStatusReporting))
   236  			})
   237  
   238  			It("eventually leads to the integration test PipelineRun's Pass status reported at MR notes", func() {
   239  				expectedNote := fmt.Sprintf("Integration test for snapshot %s and scenario %s has passed", snapshot.Name, integrationTestScenarioPass.Name)
   240  				validateNoteInMergeRequestComment(f, projectID, expectedNote, mrID)
   241  			})
   242  
   243  			It("validates the Integration test scenario PipelineRun is reported to merge request CommitStatus, and it fails", func() {
   244  				timeout = time.Second * 300
   245  				interval = time.Second * 1
   246  
   247  				Eventually(func() string {
   248  					commitStatuses, _, err := f.AsKubeAdmin.CommonController.Gitlab.GetClient().Commits.GetCommitStatuses(projectID, mrSha, nil)
   249  					Expect(err).ShouldNot(HaveOccurred())
   250  
   251  					for _, commitStatus := range commitStatuses {
   252  						commitStatusNames := strings.Split(commitStatus.Name, "/")
   253  						if len(commitStatusNames) > 2 {
   254  							if strings.Contains(integrationTestScenarioFail.Name, strings.TrimSpace(commitStatusNames[1])) {
   255  								return commitStatus.Status
   256  							}
   257  						}
   258  					}
   259  					return ""
   260  				}, timeout, interval).Should(Equal(integrationPipelineRunCommitStatusFail), fmt.Sprintf("timed out when waiting for expected commitStatus to be created for sha %s in %s repository", mrSha, componentRepoNameForStatusReporting))
   261  			})
   262  
   263  			It("eventually leads to the integration test PipelineRun's Fail status reported at MR notes", func() {
   264  				expectedNote := fmt.Sprintf("Integration test for snapshot %s and scenario %s has failed", snapshot.Name, integrationTestScenarioFail.Name)
   265  				validateNoteInMergeRequestComment(f, projectID, expectedNote, mrID)
   266  			})
   267  		})
   268  
   269  	})
   270  })
   271  
   272  // createBuildSecret creates a secret of gitlab build
   273  func createBuildSecret(f *framework.Framework, secretName string, annotations map[string]string, token string) error {
   274  	buildSecret := v1.Secret{}
   275  	buildSecret.Name = secretName
   276  	buildSecret.Labels = map[string]string{
   277  		"appstudio.redhat.com/credentials": "scm",
   278  		"appstudio.redhat.com/scm.host":    "gitlab.com",
   279  	}
   280  	if annotations != nil {
   281  		buildSecret.Annotations = annotations
   282  	}
   283  	buildSecret.Type = "kubernetes.io/basic-auth"
   284  	buildSecret.StringData = map[string]string{
   285  		"password": token,
   286  	}
   287  	_, err := f.AsKubeAdmin.CommonController.CreateSecret(f.UserNamespace, &buildSecret)
   288  	if err != nil {
   289  		return fmt.Errorf("error creating build secret: %v", err)
   290  	}
   291  	return nil
   292  }
   293  
   294  // validateNoteInMergeRequestComment verify expected note is commented in MR comment
   295  func validateNoteInMergeRequestComment(f *framework.Framework, projectID, expectedNote string, mergeRequestID int) {
   296  
   297  	var timeout, interval time.Duration
   298  
   299  	timeout = time.Minute * 10
   300  	interval = time.Second * 2
   301  
   302  	Eventually(func() bool {
   303  		// Continue here, get as argument MR ID so use in ListMergeRequestNotes
   304  		allNotes, _, err := f.AsKubeAdmin.CommonController.Gitlab.GetClient().Notes.ListMergeRequestNotes(projectID, mergeRequestID, nil)
   305  		Expect(err).ShouldNot(HaveOccurred())
   306  		for _, note := range allNotes {
   307  			if strings.Contains(note.Body, expectedNote) {
   308  				return true
   309  			}
   310  		}
   311  		return false
   312  	}, timeout, interval).Should(BeTrue(), fmt.Sprintf("timed out waiting to validate merge request note ('%s') be reported in mergerequest %d's notes", expectedNote, mergeRequestID))
   313  }