Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.hp.octane.integrations.executor.converters.MfMBTConverter Maven / Gradle / Ivy
/*
* Copyright 2017 EntIT Software LLC, a Micro Focus company, L.P.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.hp.octane.integrations.executor.converters;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hp.octane.integrations.OctaneClient;
import com.hp.octane.integrations.OctaneConfiguration;
import com.hp.octane.integrations.OctaneSDK;
import com.hp.octane.integrations.dto.DTOFactory;
import com.hp.octane.integrations.dto.connectivity.HttpMethod;
import com.hp.octane.integrations.dto.connectivity.OctaneRequest;
import com.hp.octane.integrations.dto.connectivity.OctaneResponse;
import com.hp.octane.integrations.dto.executor.impl.TestingToolType;
import com.hp.octane.integrations.dto.general.MbtData;
import com.hp.octane.integrations.dto.general.MbtDataTable;
import com.hp.octane.integrations.dto.general.MbtUnit;
import com.hp.octane.integrations.dto.general.MbtUnitParameter;
import com.hp.octane.integrations.executor.TestToRunData;
import com.hp.octane.integrations.executor.TestsToRunConverterResult;
import com.hp.octane.integrations.services.rest.OctaneRestClient;
import com.hp.octane.integrations.uft.UftTestDiscoveryUtils;
import com.hp.octane.integrations.utils.SdkStringUtils;
import org.apache.commons.codec.Charsets;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.http.HttpStatus;
import org.apache.http.entity.ContentType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.util.StringBuilderWriter;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.hp.octane.integrations.services.rest.RestService.ACCEPT_HEADER;
import static com.hp.octane.integrations.utils.SdkConstants.JobParameters.*;
/*
* Converter to uft format (MTBX)
*/
public class MfMBTConverter extends MfUftConverter {
private static final Logger logger = LogManager.getLogger(MfMBTConverter.class);
public static final String MBT_DATA = "mbtData";
public static final String MBT_PARENT_SUB_DIR = "___mbt";
public static final String MBT_DATA_NOT_INCLUDED = "mbtDataNotIncluded";
public static final Pattern specialCharsPattern = Pattern.compile("[\\/:*?\"<>|%;]");
public static final String BASE64_PREFIX = "BASE64_";
public static final String INNER_RUN_ID_PARAMETER = "runId";//should not be handled by uft
List mbtTests;
public static String encodeTestNameIfRequired(String name) {
if (name.startsWith(" ") || name.endsWith(" ") || specialCharsPattern.matcher(name).find()) {
return BASE64_PREFIX + Base64.getUrlEncoder().encodeToString(name.getBytes(Charsets.UTF_8));
} else {
return name;
}
}
public static String decodeTestNameIfRequired(String name) {
if (name.startsWith(BASE64_PREFIX)) {
byte[] decodedBytes = Base64.getUrlDecoder().decode(name.substring(BASE64_PREFIX.length()));
return new String(decodedBytes, Charsets.UTF_8);
} else {
return name;
}
}
private static boolean shouldRetrieveMbtData(List tests) {
return tests.get(0).getParameters().get(MBT_DATA).equals(MBT_DATA_NOT_INCLUDED);
}
private static Map parseSuiteRunDataJson(String responseJson) {
try {
ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper.readValue(responseJson, Map.class);
} catch (IOException e) {
throw new IllegalArgumentException("Invalid suite run data format: " + e.getMessage(), e);
}
}
private static String extractDataTableIterations(MbtData mbtData, TestToRunData testToRunData) {
String encodedIterationsAsString = "";
MbtDataTable dataTable = mbtData.getData();
if (dataTable != null && dataTable.getParameters() != null && !dataTable.getParameters().isEmpty()) {
StringBuilderWriter stringBuilderWriter = new StringBuilderWriter();
try (CSVPrinter csvPrinter = new CSVPrinter(stringBuilderWriter, CSVFormat.DEFAULT.withHeader(dataTable.getParameters().stream().toArray(String[]::new)))) {
dataTable.getIterations().forEach(iteration -> {
try {
csvPrinter.printRecord(iteration);
} catch (IOException e) {
logger.error("Failed to build data table iterations record for mbt test {}", testToRunData.getTestName(), e);
}
});
} catch (IOException e) {
logger.error("Failed to build data table iterations for mbt test {}", testToRunData.getTestName(), e);
}
String iterationsAsString = stringBuilderWriter.toString();
byte[] encodedIterations = Base64.getEncoder().encode(iterationsAsString.getBytes(StandardCharsets.UTF_8));
encodedIterationsAsString = new String(encodedIterations, StandardCharsets.UTF_8);
}
return encodedIterationsAsString;
}
private static String extractActionParameterNames(MbtUnit mbtUnit) {
List parameters = mbtUnit.getParameters();
if (parameters != null && !parameters.isEmpty()) {
StringBuilder inputParameters = new StringBuilder();
StringBuilder outputParameters = new StringBuilder();
parameters.forEach(mbtUnitParameter -> {
String parameterName = mbtUnitParameter.getName();
switch (mbtUnitParameter.getType().toUpperCase()) {
case "INPUT":
inputParameters.append(SdkStringUtils.isEmpty(mbtUnitParameter.getOutputParameter()) ?
",DataTable(\"" + parameterName + "\")" : "," + mbtUnitParameter.getOutputParameter());
break;
case "OUTPUT":
default:
outputParameters.append(",").append(parameterName);
break;
}
});
return inputParameters.append(outputParameters).toString();
} else {
return null;
}
}
/**
* if path to resource is relative to test, compute absolute path to resource
*
* @param testPath
* @param resourcePath
* @return
*/
public static String computeResourcePath(String resourcePath, String testPath) {
if (resourcePath.startsWith("..")) {
File file = new File(testPath, resourcePath);
try {
return file.getCanonicalPath();
} catch (IOException e) {
String msg = String.format("Failed to computeResourcePath for resource %s , test %s", resourcePath, testPath);
logger.error(msg);
return resourcePath;
}
}
return resourcePath;
}
@Override
public String convertInternal(List data, String executionDirectory, Map globalParameters) {
String myWorkingDir = executionDirectory + "\\" + MBT_PARENT_SUB_DIR;
handleMBTModel(data, executionDirectory, globalParameters);
return super.convertToMtbxContent(data, myWorkingDir, globalParameters);
}
@Override
protected void afterConvert(TestsToRunConverterResult result) {
result.setMbtTests(mbtTests);
}
@Override
public void enrichTestsData(List tests, Map globalParameters) {
handleMbtDataRetrieval(tests, globalParameters);
}
private void handleMBTModel(List tests, String checkoutFolder, Map globalParameters) {
//replace test name if required
for (TestToRunData data : tests) {
data.setTestName(encodeTestNameIfRequired(data.getTestName()));
}
mbtTests = new ArrayList<>();
int order = 1;
for (TestToRunData data : tests) {
String mbtDataRaw = data.getParameter(MBT_DATA);
MbtData mbtData;
if (MBT_DATA_NOT_INCLUDED.equals(mbtDataRaw)) {
throw new RuntimeException("Failed to fetch mbt data for test " + data.getTestName());
}
try {
String raw = new String(Base64.getDecoder().decode(mbtDataRaw), StandardCharsets.UTF_8);
mbtData = DTOFactory.getInstance().dtoFromJson(raw, MbtData.class);
if(mbtData.getTestingToolType().equals(TestingToolType.UFT)) { // advance package name only for uft tests. it is not relevant for codeless tests
data.setPackageName("_" + order++);
}
} catch (Exception e) {
String msg = "Failed to decode test action data " + data.getTestName() + " : " + e.getMessage();
logger.error(msg);
throw new RuntimeException(msg);
}
if (mbtData.getTestingToolType().equals(TestingToolType.UFT)) {
convertUftTest(checkoutFolder, data, mbtData);
} else {
convertCodelessTest(data, mbtData);
}
}
}
private void convertUftTest(String checkoutFolder, TestToRunData data, MbtData mbtData) {
//parse test and action names
for (int i = mbtData.getUnits().size() - 1; i >= 0; i--) {
MbtUnit mbtUnit = mbtData.getUnits().get(i);
String scmPath = mbtUnit.getPathInScm();
if (scmPath == null || !scmPath.contains(":")) {
logger.error("UnitId {} has invalid scmPath : {}, skipping", mbtUnit.getUnitId(), mbtUnit.getPathInScm());
mbtData.getUnits().remove((i));
continue;
}
String[] testAndActionParts = scmPath.split(":");//example : GUITests/f1/GUITest02:Action1
String testPath = checkoutFolder + "\\" + testAndActionParts[0];
String actionName = testAndActionParts[1];
mbtUnit.setTestPath(testPath).setActionName(actionName);
}
//build script
List scriptLinesList = new ArrayList<>();
List underlyingTestsList = new ArrayList<>();
List unitIds = new ArrayList<>();
String testLineSplitter = "'********************************************************************************************************************************************";
scriptLinesList.add("");
scriptLinesList.add(testLineSplitter);
scriptLinesList.add("");
try {
for (int i = 0; i < mbtData.getUnits().size(); i++) {
MbtUnit mbtUnit = mbtData.getUnits().get(i);
String sanitizedTestPath = sanitizeTestPath(mbtUnit.getTestPath()); // remove the action from the test path is exists
mbtUnit.setTestPath(sanitizedTestPath);
//validate test folder exist
File testFolderFile = new File(mbtUnit.getTestPath());
if (!testFolderFile.exists()) {
throw new IllegalArgumentException(String.format("Test path %s is not found. UnitId = %s.", mbtUnit.getTestPath(), mbtUnit.getUnitId()));
}
//validate that uft test folder is valid
if (UftTestDiscoveryUtils.isUftTestFolder(testFolderFile.listFiles()).isNone()) {
throw new IllegalArgumentException(String.format("Invalid test path %s. UnitId = %s.", mbtUnit.getTestPath(), mbtUnit.getUnitId()));
}
String actionParameters = extractActionParameterNames(mbtUnit);
TestResources testResources = extractTestResources(mbtUnit.getTestPath());
boolean theSameTestAsPrev = i > 0 ? mbtData.getUnits().get(i - 1).getTestPath().equals(mbtUnit.getTestPath()) : false;
if (theSameTestAsPrev) {
scriptLinesList.add("'The action belongs to the test of the previous action. Skip reloading function libraries and recovery scenarios.");
} else {
if (!testResources.functionLibraries.isEmpty()) {
scriptLinesList.add("");
scriptLinesList.add("'Add function libraries");
scriptLinesList.add("RestartFLEngine");
for (String fl : testResources.functionLibraries) {
scriptLinesList.add(String.format("LoadFunctionLibrary \"%s\"", fl));
}
}
if (!testResources.recoveryScenarios.isEmpty()) {
scriptLinesList.add("");
scriptLinesList.add("'Add recovery scenarios");
scriptLinesList.add("CleanRSManager");
String scenarios = "LoadRecoveryScenario " + testResources.recoveryScenarios.stream().
map(rs -> String.format("\"%s|%s|1|1*\"", rs.path, rs.name)).collect(Collectors.joining(","));
scriptLinesList.add(scenarios);
}
}
scriptLinesList.add("");
scriptLinesList.add("'Run action");
if (actionParameters != null) {
scriptLinesList.add(String.format("LoadAndRunAction \"%s\",\"%s\",rngAll%s", mbtUnit.getTestPath(), mbtUnit.getActionName(), actionParameters));
} else {
scriptLinesList.add(String.format("LoadAndRunAction \"%s\",\"%s\"", mbtUnit.getTestPath(), mbtUnit.getActionName()));
}
scriptLinesList.add("");
scriptLinesList.add(testLineSplitter);
scriptLinesList.add("");
//END SCRIPT
underlyingTestsList.add(mbtUnit.getTestPath());
unitIds.add(mbtUnit.getUnitId());
}
} catch (Exception e) {
logger.error("Failed to build script for test {} : {}", data.getTestName(), e.getMessage());
throw e;
}
String script = String.join("\r\n", scriptLinesList);
//ADD PARAMETERS to data table
String encodedIterationsAsString = extractDataTableIterations(mbtData, data);
MbtUftTest test = new MbtUftTest(data.getTestName(), data.getPackageName(), script, underlyingTestsList, unitIds, encodedIterationsAsString,
Collections.emptyList(), Collections.emptyList());
mbtTests.add(test);
}
private void convertCodelessTest(TestToRunData data, MbtData mbtData) {
// this will prevent codeless test to be transformed to mtbx
data.addParameters(TESTING_TOOL_TYPE_PARAMETER, TestingToolType.CODELESS.value());
MbtCodelessTest mbtCodelessTest = new MbtCodelessTest(data.getTestName());
mbtCodelessTest.setMbtDataTable(mbtData.getData());
for (MbtUnit mbtUnit : mbtData.getUnits()) {
MbtCodelessUnit mbtCodelessUnit = new MbtCodelessUnit();
mbtCodelessUnit.setUnitId(mbtUnit.getUnitId());
mbtCodelessUnit.setName(mbtUnit.getName());
mbtCodelessUnit.setOrder(mbtUnit.getOrder());
mbtCodelessUnit.setScript(mbtUnit.getScript());
mbtCodelessUnit.setParameters(mbtUnit.getParameters());
mbtCodelessTest.getUnits().add(mbtCodelessUnit);
}
mbtTests.add(mbtCodelessTest);
}
// remove action# from repository path for execution, if exists
private String sanitizeTestPath(String testPath) {
if (SdkStringUtils.isEmpty(testPath)) {
return testPath;
}
int lastIndex = testPath.lastIndexOf("\\");
if (lastIndex > -1) {
String lastPart = testPath.substring(lastIndex);
if (lastPart.toLowerCase().contains("action")) {
return testPath.substring(0, lastIndex);
}
}
return testPath;
}
private void handleMbtDataRetrieval(List tests, Map globalParameters) {
if (shouldRetrieveMbtData(tests)) {
OctaneClient octaneClient = OctaneSDK.getClientByInstanceId(globalParameters.get(OCTANE_CONFIG_ID_PARAMETER_NAME));
OctaneConfiguration octaneConfig = octaneClient.getConfigurationService().getConfiguration();
String url = octaneConfig.getUrl() + "/api" + "/shared_spaces/" + octaneConfig.getSharedSpace() +
"/workspaces/" + globalParameters.get(OCTANE_WORKSPACE_PARAMETER_NAME) +
"/suite_runs/" + globalParameters.get(SUITE_RUN_ID_PARAMETER_NAME) + "/get_suite_data";
Map headers = new HashMap<>();
headers.put(ACCEPT_HEADER, ContentType.APPLICATION_JSON.getMimeType());
headers.put(OctaneRestClient.CLIENT_TYPE_HEADER, OctaneRestClient.CLIENT_TYPE_VALUE);
OctaneRequest request = DTOFactory.getInstance()
.newDTO(OctaneRequest.class)
.setMethod(HttpMethod.GET)
.setHeaders(headers)
.setUrl(url);
try {
OctaneResponse octaneResponse = octaneClient.getRestService().obtainOctaneRestClient().execute(request);
if (octaneResponse != null && octaneResponse.getStatus() == HttpStatus.SC_OK) {
Map parsedResponse = parseSuiteRunDataJson(octaneResponse.getBody());
if (parsedResponse != null) {
for (TestToRunData test : tests) {
String runID = test.getParameter(INNER_RUN_ID_PARAMETER);
test.addParameters(MBT_DATA, parsedResponse.get(runID));
}
}
} else {
logger.error("Failed to get response {}", (octaneResponse != null ? octaneResponse.getStatus() : "(null)"));
return;
}
} catch (IOException e) {
logger.error("Failed to get response ", e);
return;
}
}
}
private TestResources extractTestResources(String testPath) {
TestResources content = new TestResources();
//ADD function libraries and recovery scenarios
try {
File tspFile = new File(testPath + "\\Test.tsp");
InputStream is = new FileInputStream(tspFile);
String xmlContent = UftTestDiscoveryUtils.extractXmlContentFromTspFile(is);
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(new InputSource(new StringReader(xmlContent)));
//FL
NodeList funcLibNodes = document.getElementsByTagName("FuncLib");
for (int i = 0; i < funcLibNodes.getLength(); i++) {
String fl = document.getElementsByTagName("FuncLib").item(i).getTextContent();
content.functionLibraries.add(computeResourcePath(fl, testPath));
}
//RC
String[] recoveryScenariosParts = document.getElementsByTagName("RecoveryScenarios").item(0).getTextContent().split("\\*");
for (String recoveryScenariosPart : recoveryScenariosParts) {
String[] rsAsArray = recoveryScenariosPart.split("\\|");
if (rsAsArray.length > 1) {
String rsPath = computeResourcePath(rsAsArray[0], testPath);
String rsName = rsAsArray[1];
content.recoveryScenarios.add(RecoveryScenario.create(rsPath, rsName));
}
}
} catch (IOException | ParserConfigurationException | SAXException e) {
logger.error("Failed to parse function libraries/recovery scenarios for tests {} : {}", testPath, e);
}
return content;
}
private static class TestResources {
List functionLibraries = new ArrayList<>();
List recoveryScenarios = new ArrayList<>();
}
private static class RecoveryScenario {
String path;
String name;
public static RecoveryScenario create(String path, String name) {
RecoveryScenario rc = new RecoveryScenario();
rc.path = path;
rc.name = name;
return rc;
}
}
}