From 2211de6254c98848e2331a0e66a3a62bea287e3e Mon Sep 17 00:00:00 2001 From: Madalin Tiutiu Date: Tue, 17 Oct 2023 14:18:35 +0300 Subject: [PATCH 1/7] Added detection for Charset Encoding --- pom.xml | 6 ++++++ .../octane/gitlab/helpers/EncodingHelper.java | 18 ++++++++++++++++++ .../gitlab/helpers/TestResultsHelper.java | 12 ++++++------ 3 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/microfocus/octane/gitlab/helpers/EncodingHelper.java diff --git a/pom.xml b/pom.xml index fa19dcc..7b1b336 100644 --- a/pom.xml +++ b/pom.xml @@ -108,6 +108,12 @@ + + com.github.albfernandez + juniversalchardet + 2.4.0 + + diff --git a/src/main/java/com/microfocus/octane/gitlab/helpers/EncodingHelper.java b/src/main/java/com/microfocus/octane/gitlab/helpers/EncodingHelper.java new file mode 100644 index 0000000..073f189 --- /dev/null +++ b/src/main/java/com/microfocus/octane/gitlab/helpers/EncodingHelper.java @@ -0,0 +1,18 @@ +package com.microfocus.octane.gitlab.helpers; + +import org.mozilla.universalchardet.UniversalDetector; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +public class EncodingHelper { + + public static String detectCharset(InputStream is) throws IOException { + return UniversalDetector.detectCharset(is); + } + + public static String detectCharset(File file) throws IOException { + return UniversalDetector.detectCharset(file); + } +} diff --git a/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java b/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java index 628987d..018df6e 100644 --- a/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java +++ b/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java @@ -103,15 +103,14 @@ public static List extractArtifactsToFiles(InputStream inputStream, String if (matcher.matches(Paths.get(entry.getName()))) { ByteArrayOutputStream entryStream = new ByteArrayOutputStream(); - try (InputStream zipEntryStream = zipFile.getInputStream(entry)) { StreamHelper.copyStream(zipEntryStream, entryStream); } File tempResultFile = File.createTempFile(entry.getName(),".xml"); - FileOutputStream f = null;//new FileOutputStream(entry.getName()); - IOUtils.copy(new ByteArrayInputStream(entryStream.toByteArray()), tempResultFile); - + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(entryStream.toByteArray()); + String s = entryStream.toString(EncodingHelper.detectCharset(byteArrayInputStream)); + IOUtils.copy(new ByteArrayInputStream(s.getBytes()), tempResultFile); result.add(tempResultFile); } } @@ -153,8 +152,9 @@ public static List> extractArtifacts(Inp try (InputStream zipEntryStream = zipFile.getInputStream(entry)) { StreamHelper.copyStream(zipEntryStream, entryStream); } - - result.add(Pair.of(entry.getName(), new ByteArrayInputStream(entryStream.toByteArray()))); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(entryStream.toByteArray()); + String s = entryStream.toString(EncodingHelper.detectCharset(byteArrayInputStream)); + result.add(Pair.of(entry.getName(), new ByteArrayInputStream(s.getBytes()))); } } return result; From 322bda259f02fa4713e9382c713bdc441408ccfb Mon Sep 17 00:00:00 2001 From: Madalin Tiutiu Date: Tue, 31 Oct 2023 10:49:51 +0200 Subject: [PATCH 2/7] Fixed Encoding and tests with failed status beeing push as Passed --- pom.xml | 6 ++++++ .../octane/gitlab/helpers/TestResultsHelper.java | 7 +++++-- .../gitlab/testresults/JunitTestResultsProvider.java | 5 ++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 7b1b336..85fafea 100644 --- a/pom.xml +++ b/pom.xml @@ -114,6 +114,12 @@ 2.4.0 + + commons-codec + commons-codec + 1.14 + + diff --git a/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java b/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java index 018df6e..15b0e8a 100644 --- a/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java +++ b/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java @@ -39,6 +39,7 @@ import org.gitlab4j.api.models.Project; import java.io.*; +import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.PathMatcher; import java.nio.file.Paths; @@ -109,7 +110,8 @@ public static List extractArtifactsToFiles(InputStream inputStream, String File tempResultFile = File.createTempFile(entry.getName(),".xml"); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(entryStream.toByteArray()); - String s = entryStream.toString(EncodingHelper.detectCharset(byteArrayInputStream)); + String encoding = EncodingHelper.detectCharset(byteArrayInputStream); + String s = entryStream.toString(encoding == null ? StandardCharsets.UTF_8.name() : encoding); IOUtils.copy(new ByteArrayInputStream(s.getBytes()), tempResultFile); result.add(tempResultFile); } @@ -153,7 +155,8 @@ public static List> extractArtifacts(Inp StreamHelper.copyStream(zipEntryStream, entryStream); } ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(entryStream.toByteArray()); - String s = entryStream.toString(EncodingHelper.detectCharset(byteArrayInputStream)); + String encoding = EncodingHelper.detectCharset(byteArrayInputStream); + String s = entryStream.toString(encoding == null ? StandardCharsets.UTF_8.name() : encoding); result.add(Pair.of(entry.getName(), new ByteArrayInputStream(s.getBytes()))); } } diff --git a/src/main/java/com/microfocus/octane/gitlab/testresults/JunitTestResultsProvider.java b/src/main/java/com/microfocus/octane/gitlab/testresults/JunitTestResultsProvider.java index dfef2c1..163da67 100644 --- a/src/main/java/com/microfocus/octane/gitlab/testresults/JunitTestResultsProvider.java +++ b/src/main/java/com/microfocus/octane/gitlab/testresults/JunitTestResultsProvider.java @@ -49,14 +49,17 @@ import javax.xml.bind.JAXBException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; +import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -167,7 +170,7 @@ private void addTestCase(List result, Testsuite ts, Testcase tc) { TestRunResult testResultStatus; if (tc.getSkipped() != null && tc.getSkipped().trim().length() > 0) { testResultStatus = TestRunResult.SKIPPED; - } else if (tc.getFailure().size() > 0) { + } else if (tc.getFailure().size() > 0 || tc.getError().size() > 0) { testResultStatus = TestRunResult.FAILED; } else { testResultStatus = TestRunResult.PASSED; From fdfb2748008576ed7736870758bcc76d8f3220b8 Mon Sep 17 00:00:00 2001 From: TiutiuMadalin <62649591+TiutiuMadalin@users.noreply.github.com> Date: Wed, 1 Nov 2023 14:36:55 +0200 Subject: [PATCH 3/7] Update parameters in TestFramework.md - US#2312137 --- docs/TestFramework.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/TestFramework.md b/docs/TestFramework.md index 7e44d68..80f07f0 100644 --- a/docs/TestFramework.md +++ b/docs/TestFramework.md @@ -2,15 +2,19 @@ 1. On your current repository (the one containing the code and the tests) create a new branch that will hold the test runner pipeline. -2. Configure the following 3 variables on the project level: - 1. testsToRun - the value does not matter. The integration will populate this variable with the selected tests in ALM Octane. +2. Configure the following variables on the project level: + 1. testsToRun - the value does not matter. The integration will populate this variable with the selected tests from ALM Octane. 2. testRunnerBranch - the value will be the name of the branch created earlier, which holds the test runner pipeline. 3. testRunnerFramework - the value should be the following: * mvnSurefire - For running JUnit/TestNG over Maven Surefire/Failsafe * uft - For running UFT-One tests using FTToolsLauncher * custom - For running tests using a custom Framework that can generate Junit results (see our examples [here](CustomTestFrameworkExample.md)) + + #### Optional Variables: 4. testRunnerCustomPattern - an optional parameter required only if the Framework is custom - - the value will be a json containing a pattern to convert the Automated Test from ALM Octane to the accepted format for the Framework + - the value will be a JSON containing a pattern to convert the Automated Test from ALM Octane to the accepted format for the Framework + 5. suiteId - the value does not matter. The integration will populate this variable with the selected Test Suite ID from ALM Octane. + 6. suiteRunId - the value does not matter. The integration will populate this variable with the executed Suite Run ID from ALM Octane. 3. In the created branch configure the `.gitlab-ci.yml` file to include the logic for running the tests received in the testsToRun variable. Example for `mvnSurefire`: @@ -54,4 +58,7 @@ As the Test Runner executes a pipeline on the GitLab side, a job entity will als Keep in mind that the Test Runner pipeline should only be executed using the Test Runner and not by manually running it from the Pipeline menu. More about ALM Octane Testing Framework here: -https://admhelp.microfocus.com/octane/en/latest/Online/Content/AdminGuide/how-setup-testing-integration.htm \ No newline at end of file +https://admhelp.microfocus.com/octane/en/latest/Online/Content/AdminGuide/how-setup-testing-integration.htm + +### Aditional variable configuration +1. suiteId - the value does not matter. The integration will populate this variable with the selected tests in ALM Octane. From be566e226cd4bb4177fad2a83e6e05120d9bb464 Mon Sep 17 00:00:00 2001 From: TiutiuMadalin <62649591+TiutiuMadalin@users.noreply.github.com> Date: Wed, 1 Nov 2023 14:44:56 +0200 Subject: [PATCH 4/7] Update format TestFramework.md --- docs/TestFramework.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/TestFramework.md b/docs/TestFramework.md index 80f07f0..c4c9332 100644 --- a/docs/TestFramework.md +++ b/docs/TestFramework.md @@ -3,20 +3,21 @@ 1. On your current repository (the one containing the code and the tests) create a new branch that will hold the test runner pipeline. 2. Configure the following variables on the project level: + #### Mandatory Variables for test runner configuration 1. testsToRun - the value does not matter. The integration will populate this variable with the selected tests from ALM Octane. 2. testRunnerBranch - the value will be the name of the branch created earlier, which holds the test runner pipeline. 3. testRunnerFramework - the value should be the following: * mvnSurefire - For running JUnit/TestNG over Maven Surefire/Failsafe * uft - For running UFT-One tests using FTToolsLauncher - * custom - For running tests using a custom Framework that can generate Junit results (see our examples [here](CustomTestFrameworkExample.md)) - - #### Optional Variables: + * custom - For running tests using a custom Framework that can generate Junit results (see our examples [here](CustomTestFrameworkExample.md))``` + + #### Optional Variables 4. testRunnerCustomPattern - an optional parameter required only if the Framework is custom - the value will be a JSON containing a pattern to convert the Automated Test from ALM Octane to the accepted format for the Framework 5. suiteId - the value does not matter. The integration will populate this variable with the selected Test Suite ID from ALM Octane. 6. suiteRunId - the value does not matter. The integration will populate this variable with the executed Suite Run ID from ALM Octane. -3. In the created branch configure the `.gitlab-ci.yml` file to include the logic for running the tests received in the testsToRun variable. +4. In the created branch configure the `.gitlab-ci.yml` file to include the logic for running the tests received in the testsToRun variable. Example for `mvnSurefire`: ``` image: maven:3.3.9-jdk-8 From 349299ea679af9e31769607e4c425d2543b550f6 Mon Sep 17 00:00:00 2001 From: Madalin Tiutiu Date: Tue, 7 Nov 2023 16:19:49 +0200 Subject: [PATCH 5/7] Bump up version & fixed encoding --- pom.xml | 2 +- .../octane/gitlab/api/EventListener.java | 23 +++++++++++-------- .../gitlab/helpers/TestResultsHelper.java | 15 +++++++----- .../testresults/JunitTestResultsProvider.java | 20 +++++++--------- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/pom.xml b/pom.xml index 85fafea..c76f031 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.microfocus.octane.ciplugins octane-gitlab-service - 23.3.1 + 23.3.2 ALM Octane GitLab CI Service diff --git a/src/main/java/com/microfocus/octane/gitlab/api/EventListener.java b/src/main/java/com/microfocus/octane/gitlab/api/EventListener.java index 2d41db3..2ff675f 100644 --- a/src/main/java/com/microfocus/octane/gitlab/api/EventListener.java +++ b/src/main/java/com/microfocus/octane/gitlab/api/EventListener.java @@ -83,7 +83,9 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Response; import javax.xml.transform.TransformerConfigurationException; -import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; @@ -307,16 +309,19 @@ private void sendCodeCoverage(long projectId, Project project, Job job) throws G String octaneJobId = project.getPathWithNamespace().toLowerCase() + "/" + job.getName(); String octaneBuildId = job.getId().toString(); - try (InputStream artifactsStream = gitLabApi.getJobApi() - .downloadArtifactsFile(projectId, job.getId())) { - List> coverageResultFiles = - TestResultsHelper.extractArtifacts(artifactsStream, "glob:" + coverageReportFilePattern); + try (InputStream artifactsStream = gitLabApi.getJobApi().downloadArtifactsFile(projectId, job.getId())) { + List coverageResultFiles = + TestResultsHelper.extractArtifactsToFiles(artifactsStream, "glob:" + coverageReportFilePattern); if (Objects.nonNull(coverageResultFiles) && coverageResultFiles.size() > 0) { - coverageResultFiles.forEach( - coverageFile -> OctaneSDK.getClients().forEach(client -> client.getCoverageService() - .pushCoverage(octaneJobId, octaneBuildId, CoverageReportType.JACOCOXML, - coverageFile.getValue()))); + coverageResultFiles.forEach(coverageFile -> OctaneSDK.getClients().forEach(client -> { + try { + client.getCoverageService().pushCoverage(octaneJobId, octaneBuildId, CoverageReportType.JACOCOXML, + new FileInputStream(coverageFile)); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + })); } } catch (GitLabApiException | IOException exception) { log.error(exception.getMessage()); diff --git a/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java b/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java index 15b0e8a..33de1e2 100644 --- a/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java +++ b/src/main/java/com/microfocus/octane/gitlab/helpers/TestResultsHelper.java @@ -41,6 +41,7 @@ import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; +import java.nio.file.Files; import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.util.*; @@ -111,8 +112,9 @@ public static List extractArtifactsToFiles(InputStream inputStream, String File tempResultFile = File.createTempFile(entry.getName(),".xml"); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(entryStream.toByteArray()); String encoding = EncodingHelper.detectCharset(byteArrayInputStream); - String s = entryStream.toString(encoding == null ? StandardCharsets.UTF_8.name() : encoding); - IOUtils.copy(new ByteArrayInputStream(s.getBytes()), tempResultFile); + String xml = entryStream.toString(encoding == null ? StandardCharsets.UTF_8.name() : encoding); + xml = xml.trim().replaceFirst("^([\\W]+)<", "<"); + Files.write(tempResultFile.toPath(), xml.getBytes(encoding == null ? StandardCharsets.UTF_8.name() : encoding)); result.add(tempResultFile); } } @@ -127,7 +129,7 @@ public static List extractArtifactsToFiles(InputStream inputStream, String } } - public static List> extractArtifacts(InputStream inputStream, String testResultsFilePattern) { + public static List> extractArtifacts(InputStream inputStream, String testResultsFilePattern) { PathMatcher matcher = FileSystems.getDefault() .getPathMatcher(testResultsFilePattern); File tempFile = null; @@ -142,7 +144,7 @@ public static List> extractArtifacts(Inp ZipFile zipFile = new ZipFile(tempFile); - List> result = new LinkedList<>(); + List> result = new LinkedList<>(); Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { @@ -156,8 +158,9 @@ public static List> extractArtifacts(Inp } ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(entryStream.toByteArray()); String encoding = EncodingHelper.detectCharset(byteArrayInputStream); - String s = entryStream.toString(encoding == null ? StandardCharsets.UTF_8.name() : encoding); - result.add(Pair.of(entry.getName(), new ByteArrayInputStream(s.getBytes()))); + String xml = entryStream.toString(encoding != null ? encoding : StandardCharsets.UTF_8.name()); + xml = xml.trim().replaceFirst("^([\\W]+)<", "<"); + result.add(Pair.of(entry.getName(), xml)); } } return result; diff --git a/src/main/java/com/microfocus/octane/gitlab/testresults/JunitTestResultsProvider.java b/src/main/java/com/microfocus/octane/gitlab/testresults/JunitTestResultsProvider.java index 163da67..40db1db 100644 --- a/src/main/java/com/microfocus/octane/gitlab/testresults/JunitTestResultsProvider.java +++ b/src/main/java/com/microfocus/octane/gitlab/testresults/JunitTestResultsProvider.java @@ -49,14 +49,11 @@ import javax.xml.bind.JAXBException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.StringReader; @@ -101,17 +98,16 @@ public List createAndGetTestList(InputStream artifactFiles){ if(TestResultsHelper.isFilePatternExist(testResultsFilePattern)){ try { - List> artifacts = TestResultsHelper.extractArtifacts(artifactFiles,testResultsFilePattern); + List> artifacts = TestResultsHelper.extractArtifacts(artifactFiles,testResultsFilePattern); JAXBContext jaxbContext = JAXBContext.newInstance(Testsuites.class); - for (Map.Entry artifact : artifacts) { + for (Map.Entry artifact : artifacts) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(new InputSource(artifact.getValue())); + Document doc = db.parse(new InputSource(new StringReader(artifact.getValue()))); String rootTagName = doc.getDocumentElement().getTagName().toLowerCase(); - artifact.getValue().reset(); switch (rootTagName) { case "testsuites": case "testsuite": @@ -120,8 +116,8 @@ public List createAndGetTestList(InputStream artifactFiles){ case "test-run": case "test-results": ByteArrayOutputStream os = new ByteArrayOutputStream(); - nunitTransformer.transform(new StreamSource(artifact.getValue()), new StreamResult(os)); - unmarshallAndAddToResults(result, jaxbContext, new ByteArrayInputStream(os.toByteArray())); + nunitTransformer.transform(new StreamSource(new StringReader(artifact.getValue())), new StreamResult(os)); + unmarshallAndAddToResults(result, jaxbContext, os.toString()); break; default: log.error(String.format("Artifact %s: unknown test result format that starts with the <%s> tag", artifact.getKey(), rootTagName)); @@ -143,7 +139,7 @@ public boolean createTestList(Project project, Job job, InputStream artifactFile if(TestResultsHelper.isFilePatternExist(testResultsFilePattern)){ try { - List> artifacts = TestResultsHelper.extractArtifacts(artifactFiles,testResultsFilePattern); + List> artifacts = TestResultsHelper.extractArtifacts(artifactFiles,testResultsFilePattern); if(artifacts!=null && !artifacts.isEmpty()){ TestResultsHelper.pushTestResultsKey(project,job); return true; @@ -157,8 +153,8 @@ public boolean createTestList(Project project, Job job, InputStream artifactFile return false; } - private void unmarshallAndAddToResults(List result, JAXBContext jaxbContext, ByteArrayInputStream artifact) throws JAXBException { - Object ots = jaxbContext.createUnmarshaller().unmarshal(artifact); + private void unmarshallAndAddToResults(List result, JAXBContext jaxbContext, String artifact) throws JAXBException { + Object ots = jaxbContext.createUnmarshaller().unmarshal(new StringReader(artifact)); if (ots instanceof Testsuites) { ((Testsuites) ots).getTestsuite().forEach(ts -> ts.getTestcase().forEach(tc -> addTestCase(result, ts, tc))); } else if (ots instanceof Testsuite) { From adec1c9212dbb730160b8430a0abb6b7327046e2 Mon Sep 17 00:00:00 2001 From: Madalin Tiutiu Date: Tue, 7 Nov 2023 16:21:34 +0200 Subject: [PATCH 6/7] Fixed json security issues --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c76f031..481ebaa 100644 --- a/pom.xml +++ b/pom.xml @@ -233,7 +233,7 @@ org.json json - 20230227 + [20231013,) integrations-sdk From eb554f4238c6816c523e51baf0e15fa89bdab706 Mon Sep 17 00:00:00 2001 From: Madalin Tiutiu Date: Tue, 7 Nov 2023 17:00:30 +0200 Subject: [PATCH 7/7] Fixed dependecies --- pom.xml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 481ebaa..4d25166 100644 --- a/pom.xml +++ b/pom.xml @@ -114,12 +114,6 @@ 2.4.0 - - commons-codec - commons-codec - 1.14 - - @@ -233,7 +227,7 @@ org.json json - [20231013,) + 20231013 integrations-sdk