
com.seleniumtests.connectors.extools.Uft Maven / Gradle / Ivy
package com.seleniumtests.connectors.extools;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.seleniumtests.util.logging.Sys;
import org.apache.commons.io.FileUtils;
import org.jdom2.*;
import org.jdom2.input.SAXBuilder;
import org.jsoup.Jsoup;
import org.testng.Reporter;
import org.xml.sax.InputSource;
import com.seleniumtests.connectors.selenium.SeleniumGridConnector;
import com.seleniumtests.core.SeleniumTestsContextManager;
import com.seleniumtests.core.TestTasks;
import com.seleniumtests.customexception.ConfigurationException;
import com.seleniumtests.customexception.ScenarioException;
import com.seleniumtests.driver.DriverMode;
import com.seleniumtests.reporter.logger.TestAction;
import com.seleniumtests.reporter.logger.TestMessage;
import com.seleniumtests.reporter.logger.TestMessage.MessageType;
import com.seleniumtests.reporter.logger.TestStep;
import com.seleniumtests.util.logging.ScenarioLogger;
/**
* Connector for executing UFT tests either locally or remotely on selenium grid
*
* @author S047432
*/
public class Uft {
private static final ScenarioLogger logger = ScenarioLogger.getScenarioLogger(Uft.class);
private static final String START_LOGS = "_____OUTPUT_____";
private static final String END_LOGS = "_____ENDOUTPUT_____";
private static final String SCRIPT_NAME = "uft.vbs";
private String almServer;
private String almUser;
private String almPassword;
private String almDomain;
private String almProject;
private String scriptPath;
private String scriptName;
private boolean killUftOnStartup = true;
private boolean loaded = false;
Map parameters = new HashMap<>();
;
/**
* @param scriptPath path to the script, either local or from ALM. If test is
* from ALM, prefix it with '[QualityCenter]'. e.g:
* '[QualityCenter]Subject\TOOLS\TestsFoo\foo'
*/
public Uft(String scriptPath) {
this.scriptPath = scriptPath;
this.scriptName = new File(scriptPath).getName();
}
public Uft(String almServer, String almUser, String almPassword, String almDomain, String almProject, String scriptPath) {
this.scriptPath = scriptPath;
this.scriptName = new File(scriptPath).getName();
this.almServer = almServer;
this.almUser = almUser;
this.almPassword = almPassword;
this.almDomain = almDomain;
this.almProject = almProject;
}
public String getScriptPath() {
return scriptPath;
}
public Map getParameters() {
return parameters;
}
public void setParameters(Map parameters) {
this.parameters = parameters;
}
public void loadScript(boolean killUftOnStartup) {
this.killUftOnStartup = killUftOnStartup;
List args = prepareArguments(true, false);
TestTasks.executeCommand("cscript.exe", 60, null, args.toArray(new String[]{}));
loaded = true;
}
/**
* Executes an UFT script with timeout
*
* @param timeout timeout in seconds for UFT execution
* @return the generated test step
*/
public List executeScript(int timeout, Map parameters) {
if (!loaded) {
throw new IllegalStateException("Test script has not been loaded. Call 'loadScript' before");
}
this.parameters = parameters;
String output = TestTasks.executeCommand("cscript.exe", timeout, null, prepareArguments(false, true).toArray(new String[]{}));
// when execution ends, UFT is stopped
loaded = false;
return analyseOutput(output);
}
/**
* Prepare list of arguments
*
* @param load if true, add '/load'
* @param execute if true, add '/execute'
* @return
*/
public List prepareArguments(boolean load, boolean execute) {
// copy uft.vbs to disk
String vbsPath;
try {
File tempFile = Files.createTempDirectory("uft").resolve(SCRIPT_NAME).toFile();
tempFile.deleteOnExit();
FileUtils.copyInputStreamToFile(
Thread.currentThread().getContextClassLoader().getResourceAsStream("uft/" + SCRIPT_NAME), tempFile);
vbsPath = tempFile.getAbsolutePath();
} catch (IOException e) {
throw new ScenarioException("Error sending UFT script to grid node: " + e.getMessage());
}
if (SeleniumTestsContextManager.getThreadContext().getRunMode() == DriverMode.GRID) {
SeleniumGridConnector gridConnector = SeleniumTestsContextManager.getThreadContext().getSeleniumGridConnector();
if (gridConnector != null) {
vbsPath = Paths.get(gridConnector.uploadFileToNode(vbsPath, true), SCRIPT_NAME).toString();
} else {
throw new ScenarioException("No grid connector present, executing UFT script needs a browser to be initialized");
}
}
List args = new ArrayList<>();
args.add(vbsPath);
args.add(scriptPath);
if (execute) {
args.add("/execute");
parameters.forEach((key, value) -> args.add(String.format("\"%s=%s\"", key, value)));
}
if (load) {
if (almServer != null && almUser != null && almPassword != null && almDomain != null && almProject != null) {
args.add("/server:" + almServer);
args.add("/user:" + almUser);
args.add("/password:" + almPassword);
args.add("/domain:" + almDomain);
args.add("/project:" + almProject);
} else if (almServer != null || almUser != null || almPassword != null || almDomain != null || almProject != null) {
throw new ConfigurationException(
"All valuers pour ALM connection must be provided: server, user, password, domain and project");
}
args.add("/load");
if (killUftOnStartup) {
args.add("/clean");
}
}
return args;
}
/**
* Analyze Result.xml content
*
* @param output the Result.xml content as a string // * @param duration
* duration of the execution
* @return
*/
public List analyseOutput(String output) {
StringBuilder uftOutput = new StringBuilder();
List stepList = new ArrayList<>();
boolean logging = false;
for (String line : output.split("\n")) {
line = line.trim();
if (line.contains(START_LOGS)) {
logging = true;
continue;
} else if (line.contains(END_LOGS)) {
logging = false;
}
if (logging) {
uftOutput.append(line);
}
}
stepList = readXmlResult(uftOutput.toString());
return stepList;
}
/**
* Read an action element
*
* // * @param parentStep
*
* @param actionElement
* @throws DataConversionException
*/
private TestStep readAction(Element actionElement) throws DataConversionException {
Element data = actionElement.getChild("Data");
// data null au second passage parce que pas de balise data après
TestStep actionStep = new TestStep("UFT: " + data.getChild("Name").getValue().trim(), Reporter.getCurrentTestResult(), new ArrayList<>(), false);
if (data != null && data.getChild("Result").getValue().contains("Failed")) {
actionStep.setFailed(true);
}
for (Element element : actionElement.getChildren()) {
if ("Data".equals(element.getName())) { }
else if (element.getAttributeValue("type").equals("Action")) {
TestStep readStep = readAction(element);
actionStep.addStep(readStep);
} else if (element.getAttributeValue("type").equals("Step")) {
TestAction readAction = readStep(element);
actionStep.addAction(readAction);
} else if (element.getAttributeValue("type").equals("Context")) {
TestStep readStep = readAction(element);
actionStep.addStep(readStep);
} else if (element.getAttributeValue("type").equals("User")) {
TestStep readStep = readAction(element);
actionStep.addStep(readStep);
}
}
return actionStep;
}
/**
* Read a step element
*
* // * @param parentStep
*
* @param stepElement
*/
private TestAction readStep(Element stepElement) {
String stepDescription = "";
TestAction stepAction;
List stepList = stepElement.getChildren("ReportNode");
if (stepElement.getChild("Data").getChild("Description") != null) {
if (!stepElement.getChild("Data").getChild("Description").getContent().isEmpty()) {
org.jsoup.nodes.Document htmlDoc = Jsoup.parseBodyFragment(stepElement.getChild("Data").getChildText("Description"));
String details = htmlDoc.text();
stepDescription = String.format("%s: %s", stepElement.getChild("Data").getChildText("Name"), details).trim();
}
} else {
stepDescription = String.format(stepElement.getChild("Data").getChildText("Name")).trim();
}
if (stepList.isEmpty()) {
stepAction = new TestAction(stepDescription, false, new ArrayList<>());
} else {
stepAction = new TestStep(stepDescription, Reporter.getCurrentTestResult(), new ArrayList<>(), false);
for (Element subStepElement : stepElement.getChildren("ReportNode")) {
TestAction readAction = readStep(subStepElement);
((TestStep) stepAction).addAction(readAction);
}
}
return stepAction;
}
public List readXmlResult(String xmlString) {
Document document;
SAXBuilder builder = new SAXBuilder();
List listStep = new ArrayList<>();
try {
String xml = xmlString.substring(xmlString.indexOf("<"));
String xml10pattern = "[^"
+ "\u0009\r\n"
+ "\u0020-\uD7FF"
+ "\uE000-\uFFFD"
+ "\ud800\udc00-\udbff\udfff"
+ "]";
xml = xml.replaceAll(xml10pattern, "");
document = builder.build(new InputSource(new StringReader(xml))); // we skip BOM by searching the first "<" character
Element docElement = document.getRootElement().getChild("ReportNode");
Element elementToIterate = docElement.getChild("ReportNode");
Element iterationChild = elementToIterate.getChild("ReportNode");
Element data = docElement.getChild("Data");
if (!iterationChild.getChildren("ReportNode").isEmpty()) {
elementToIterate = iterationChild;
}
for (Element element : elementToIterate.getChildren()) {
if ("ReportNode".equals(element.getName())) {
TestStep readStep = readAction(element);
listStep.add(readStep);
}
// else if ("Data".equals(element.getName())) {
// readStep(element);
// }
}
} catch (IndexOutOfBoundsException e) {
addStepWithoutXml(listStep, "Invalid XML data: ", e);
} catch (JDOMException | IOException e) {
addStepWithoutXml(listStep, "Could not read UFT report: ", e);
}
return listStep;
}
private void addStepWithoutXml(List listStep, String messageException, Exception e) {
logger.error(messageException + e.getMessage());
TestStep readStep = new TestStep("UFT: " + scriptName, Reporter.getCurrentTestResult(), new ArrayList<>(), false);
readStep.addMessage(new TestMessage(messageException + e.getMessage(), MessageType.ERROR));
listStep.add(readStep);
}
public void setKillUftOnStartup(boolean killUftOnStartup) {
this.killUftOnStartup = killUftOnStartup;
}
public boolean isKillUftOnStartup() {
return killUftOnStartup;
}
}