diff --git a/src/main/java/com/microfocus/application/automation/tools/octane/tests/build/BuildHandlerUtils.java b/src/main/java/com/microfocus/application/automation/tools/octane/tests/build/BuildHandlerUtils.java index 671bc4375..93322813b 100644 --- a/src/main/java/com/microfocus/application/automation/tools/octane/tests/build/BuildHandlerUtils.java +++ b/src/main/java/com/microfocus/application/automation/tools/octane/tests/build/BuildHandlerUtils.java @@ -62,8 +62,8 @@ import java.io.File; import java.io.IOException; +import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; /** @@ -125,6 +125,37 @@ public static FilePath getWorkspace(Run run) { logger.error("BuildHandlerUtils.getWorkspace - run is not handled. Run type : " + run.getClass()); return null; } + public static Set getWorkspaces(Run run) { + if (run.getExecutor() != null && run.getExecutor().getCurrentWorkspace() != null) { + return Collections.singleton(run.getExecutor().getCurrentWorkspace()); + } + if (run instanceof AbstractBuild) { + return Collections.singleton(((AbstractBuild) run).getWorkspace()); + } + Set workspaces = new HashSet<>(); + if (run instanceof WorkflowRun) { + FlowExecution fe = ((WorkflowRun) run).getExecution(); + if (fe != null) { + FlowGraphWalker w = new FlowGraphWalker(fe); + for (FlowNode n : w) { + WorkspaceAction action = n.getAction(WorkspaceAction.class); + if (action != null) { + FilePath workspace = action.getWorkspace(); + if (workspace == null) { + workspace = handleWorkspaceActionWithoutWorkspace(action); + } + workspaces.add(workspace); + } + } + } + } + + if(workspaces.isEmpty()) { + logger.error("BuildHandlerUtils.getWorkspaces - run is not handled. Run type : " + run.getClass()); + } + + return workspaces; + } private static FilePath handleWorkspaceActionWithoutWorkspace(WorkspaceAction action) { logger.error("Found WorkspaceAction without workspace"); diff --git a/src/main/java/com/microfocus/application/automation/tools/octane/tests/junit/JUnitExtension.java b/src/main/java/com/microfocus/application/automation/tools/octane/tests/junit/JUnitExtension.java index a60bd9a94..e29f7219a 100644 --- a/src/main/java/com/microfocus/application/automation/tools/octane/tests/junit/JUnitExtension.java +++ b/src/main/java/com/microfocus/application/automation/tools/octane/tests/junit/JUnitExtension.java @@ -71,6 +71,7 @@ import java.nio.file.Paths; import java.util.*; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static com.hp.octane.integrations.utils.SdkConstants.JobParameters.OCTANE_CONFIG_ID_PARAMETER_NAME; @@ -194,6 +195,7 @@ private static class GetJUnitTestResults implements FilePath.FileCallable moduleDetection; private long buildStarted; private FilePath workspace; + private Set allWorkspaces; private boolean stripPackageAndClass; private String sharedCheckOutDirectory; private Pattern testParserRegEx; @@ -201,14 +203,15 @@ private static class GetJUnitTestResults implements FilePath.FileCallable nodeNames = new HashSet<>(); public GetJUnitTestResults(Run build, HPRunnerType hpRunnerType, List reports, boolean stripPackageAndClass, String jenkinsRootUrl) throws IOException, InterruptedException { this.reports = reports; this.filePath = new FilePath(build.getRootDir()).createTempFile(TEMP_TEST_RESULTS_FILE_NAME_PREFIX, null); this.buildStarted = build.getStartTimeInMillis(); this.workspace = BuildHandlerUtils.getWorkspace(build); + this.allWorkspaces = BuildHandlerUtils.getWorkspaces(build); this.stripPackageAndClass = stripPackageAndClass; this.hpRunnerType = hpRunnerType; this.jenkinsRootUrl = jenkinsRootUrl; @@ -230,22 +233,31 @@ public GetJUnitTestResults(Run build, HPRunnerType hpRunnerType, List nodes = allWorkspaces.stream() + .map(JenkinsUtils::getCurrentNode) + .collect(Collectors.toList()); + nodes.forEach(node -> this.nodeNames.add(node != null && !node.getNodeName().isEmpty() ? node.getNodeName() : "")); //extract folder names for created tests - String reportFolder = buildRootDir + "/archive/UFTReport" + - (StringUtils.isNotEmpty(this.nodeName) ? "/" + this.nodeName : ""); + + List reportFolders = new ArrayList<>(); + this.nodeNames.forEach(nodeName -> + reportFolders.add(buildRootDir + "/archive/UFTReport" + (StringUtils.isNotEmpty(nodeName) ? "/" + nodeName : ""))); + List testFolderNames = new ArrayList<>(); testFolderNames.add(build.getRootDir().getAbsolutePath()); - File reportFolderFile = new File(reportFolder); - if (reportFolderFile.exists()) { - File[] children = reportFolderFile.listFiles(); - if (children != null) { - for (File child : children) { - testFolderNames.add(child.getName()); + reportFolders.forEach(reportFolder ->{ + File reportFolderFile = new File(reportFolder); + if (reportFolderFile.exists()) { + File[] children = reportFolderFile.listFiles(); + if (children != null) { + for (File child : children) { + testFolderNames.add(child.getParentFile().getName() + "/" + child.getName()); + } } } - } + }); + additionalContext = testFolderNames; } if (HPRunnerType.StormRunnerLoad.equals(hpRunnerType)) { @@ -292,7 +304,9 @@ public FilePath invoke(File f, VirtualChannel channel) throws IOException, Inter try { for (FilePath report : reports) { - JUnitXmlIterator iterator = new JUnitXmlIterator(report.read(), moduleDetection, workspace, sharedCheckOutDirectory, jobName, buildId, buildStarted, stripPackageAndClass, hpRunnerType, jenkinsRootUrl, additionalContext,testParserRegEx, octaneSupportsSteps,nodeName); + JUnitXmlIterator iterator = new JUnitXmlIterator(report.read(), moduleDetection, workspace, sharedCheckOutDirectory, jobName, + buildId, buildStarted, stripPackageAndClass, hpRunnerType, jenkinsRootUrl, additionalContext, + testParserRegEx, octaneSupportsSteps, nodeNames); while (iterator.hasNext()) { oos.writeObject(iterator.next()); } diff --git a/src/main/java/com/microfocus/application/automation/tools/octane/tests/junit/JUnitXmlIterator.java b/src/main/java/com/microfocus/application/automation/tools/octane/tests/junit/JUnitXmlIterator.java index d28c0c6eb..723b77aa9 100644 --- a/src/main/java/com/microfocus/application/automation/tools/octane/tests/junit/JUnitXmlIterator.java +++ b/src/main/java/com/microfocus/application/automation/tools/octane/tests/junit/JUnitXmlIterator.java @@ -119,13 +119,13 @@ public class JUnitXmlIterator extends AbstractXmlIterator { private String stepName; private ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); private Map testNameToCodelessResultMap = new HashMap<>(); - private String nodeName; + private Set nodeNames; private final int ERROR_MESSAGE_MAX_SIZE = System.getProperty("octane.sdk.tests.error_message_max_size") != null ? Integer.parseInt(System.getProperty("octane.sdk.tests.error_message_max_size")) : 512*512; private final int ERROR_DETAILS_MAX_SIZE = System.getProperty("octane.sdk.tests.error_details_max_size") != null ? Integer.parseInt(System.getProperty("octane.sdk.tests.error_details_max_size")) : 512*512; - public JUnitXmlIterator(InputStream read, List moduleDetection, FilePath workspace, String sharedCheckOutDirectory, String jobName, String buildId, long buildStarted, boolean stripPackageAndClass, HPRunnerType hpRunnerType, String jenkinsRootUrl, Object additionalContext, Pattern testParserRegEx, boolean octaneSupportsSteps,String nodeName) throws XMLStreamException { + public JUnitXmlIterator(InputStream read, List moduleDetection, FilePath workspace, String sharedCheckOutDirectory, String jobName, String buildId, long buildStarted, boolean stripPackageAndClass, HPRunnerType hpRunnerType, String jenkinsRootUrl, Object additionalContext, Pattern testParserRegEx, boolean octaneSupportsSteps,Set nodeNames) throws XMLStreamException { super(read); this.stripPackageAndClass = stripPackageAndClass; this.moduleDetection = moduleDetection; @@ -139,7 +139,7 @@ public JUnitXmlIterator(InputStream read, List moduleDetection, this.additionalContext = additionalContext; this.testParserRegEx = testParserRegEx; this.octaneSupportsSteps = octaneSupportsSteps; - this.nodeName = nodeName; + this.nodeNames = nodeNames; } private static long parseTime(String timeString) { @@ -261,6 +261,10 @@ private void handleJUnitTest(XMLEvent event) throws XMLStreamException, IOExcept } String cleanedTestName = cleanTestName(testName); + String nodeName = ""; + if(!nodeNames.isEmpty()){ + nodeName = nodeNames.stream().findFirst().get(); + } boolean testReportCreated = true; if (additionalContext != null && additionalContext instanceof List) { //test folders are appear in the following format GUITest1[1], while [1] number of test. It possible that tests with the same name executed in the same job @@ -268,17 +272,26 @@ private void handleJUnitTest(XMLEvent event) throws XMLStreamException, IOExcept //We assume that test folders are sorted so in this section, once we found the test folder, we remove it from collection , in order to find the second instance in next iteration List createdTests = (List) additionalContext; String searchFor = cleanedTestName + "["; - Optional optional = createdTests.stream().filter(str -> str.startsWith(searchFor)).findFirst(); + Optional optional = createdTests.stream().filter(str -> str.contains(searchFor)).findFirst(); if (optional.isPresent()) { - cleanedTestName = optional.get(); - createdTests.remove(cleanedTestName); + String nodeTestString = optional.get(); + if(nodeTestString.contains("/")){ + String node = nodeTestString.split("/")[0]; + if (nodeNames.contains(node)) { + nodeName = node; + } + + cleanedTestName = nodeTestString.split("/")[1]; + createdTests.remove(nodeTestString); + } + } testReportCreated = optional.isPresent(); } if (testReportCreated) { final String basePath = ((List) additionalContext).get(0); - String nodeNameSubFolder = StringUtils.isNotEmpty(this.nodeName) ? nodeName +"/" : ""; + String nodeNameSubFolder = StringUtils.isNotEmpty(nodeName) ? nodeName +"/" : ""; uftResultFilePath = Paths.get(basePath, "archive", "UFTReport", nodeNameSubFolder, cleanedTestName, "/Result/run_results.xml").toFile().getCanonicalPath(); externalURL = jenkinsRootUrl + "job/" + jobName + "/" + buildId + "/artifact/UFTReport/" + nodeNameSubFolder + cleanedTestName + "/Result/run_results.html"; } else {