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 }