/*
+----------------------------------------------------------------------+
| Class: CLauncher |
| |
| Developper: Eric Gavaldo (eric.gavaldo@xqual.com) |
| Version: 1.7 |
+----------------------------------------------------------------------+
*/
package com.xqual.xlauncher.selenium_java;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Vector;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.xqual.xagent.launcher.CExecutionStep;
import com.xqual.xagent.launcher.CLauncher;
import com.xqual.xagent.launcher.CParamParsingException;
import com.xqual.xagent.launcher.CReturnStatus;
import com.xqual.xagent.launcher.runner.CRunner;
import com.xqual.xagent.launcher.runner.IRunner;
import com.xqual.xcommon.CAttribute;
import com.xqual.xcommon.CXmlDocumentFactory;
import com.xqual.xcommon.IConstantsResults;
import com.xqual.xcommon.utils.CFileUtils;
import com.xqual.xcommon.utils.CUtils;
/**
* The CLauncherImpl implementation of ILauncher for Selenium Java.
* @author egavaldo
*/
public class CLauncherImpl extends CLauncher implements IConstantsResults {
// +==============================================================+
// | Attributes |
// +==============================================================+
static final String TRACE_HEADER = "{selenium java } ";
static final String TRACE_FILE_NAME = "selenium_java_traces.txt";
static final short JUNIT_FRAMEWORK = 1;
static final short TESTNG_FRAMEWORK = 2;
// parameters impacting executing at run time set by the test operator
private String testRootPath;
private String additionalClasspath;
private String javaInstallPath;
private String seleniumServerJarPath;
private String seleniumServerOptions;
private String javaClientDriverJarPath;
private String executionFramework;
private String junitJarPath;
private String testngJarPath;
private short framework;
private String interpreter;
private File workingDir;
private File seleniumServerTraceFile;
private CRunner seleniumServer = null;
private static final String JUNIT3_RUNNER_CLASS = "junit.textui.TestRunner";
private static final String JUNIT4_RUNNER_CLASS = "org.junit.runner.JUnitCore";
private static final String TESTNG_RUNNER_CLASS = "org.testng.TestNG";
private static final String JAVA_INTERPRETER_EXE = CUtils.getExecutableName("java");
private static final char CLASSPATH_DELIMITER = CUtils.getClasspathDelimiterChar();
// +==============================================================+
// | Constructors |
// +==============================================================+
public CLauncherImpl() {
super(TRACE_HEADER);
}
// +==============================================================+
// | Methods |
// +==============================================================+
public CReturnStatus initialize(int sutId, String sutName, String sutVersion) {
setSutDetails(sutId, sutName, sutVersion);
setDefaultTestcaseMustBeCreated(true); // if there is not testcase, let the systems create a default one
// check the configuration sent by the manager
printConfiguration();
Vector executionSteps = new Vector();
try {
// retrieve the parameters we need
testRootPath = getStringParamValue("General", "Test root path"); // i.e. Y:/XStudio/build/tmp/eclipse_classes
additionalClasspath = getStringParamValue("General", "Additional classpath"); // i.e. Y:/XStudio/build/lib/javaws-1_2-dev/jnlp.jar
javaInstallPath = getStringParamValue("Selenium - Java", "Java install path"); // i.e. C:/Program Files/Java/jdk1.6.0_17
seleniumServerJarPath = getStringParamValue("Selenium - Java", "Server JAR path"); // i.e. Y:/Externals/Selenium-1.0/selenium-remote-control-1.0.1/selenium-server-1.0.1/selenium-server.jar
javaClientDriverJarPath = getStringParamValue("Selenium - Java", "Java client driver JAR path"); // i.e. Y:/Externals/Selenium-1.0/selenium-remote-control-1.0.1/selenium-java-client-driver-1.0.1/selenium-java-client-driver.jar
seleniumServerOptions = getStringParamValue("Selenium - Java", "Server options");
executionFramework = getStringParamValue("Selenium - Java", "Execution framework"); // i.e. JUnit4
if (executionFramework.equals("JUnit3")) {
framework = JUNIT_FRAMEWORK;
junitJarPath = getStringParamValue("JUnit", "JUnit jar path"); // i.e. Y:/XStudio/build/lib/junit-4.7/junit-4.7.jar
interpreter = CFileUtils.quoteFilePath(javaInstallPath + "/bin/" + JAVA_INTERPRETER_EXE) + " " +
"-classpath " + CFileUtils.quoteFilePath(junitJarPath + CLASSPATH_DELIMITER + additionalClasspath + CLASSPATH_DELIMITER + javaClientDriverJarPath + CLASSPATH_DELIMITER + testRootPath) + " " +
JUNIT3_RUNNER_CLASS + " ";
} else if (executionFramework.equals("JUnit4")) {
framework = JUNIT_FRAMEWORK;
junitJarPath = getStringParamValue("JUnit", "JUnit jar path"); // i.e. Y:/XStudio/build/lib/junit-4.7/junit-4.7.jar
interpreter = CFileUtils.quoteFilePath(javaInstallPath + "/bin/" + JAVA_INTERPRETER_EXE) + " " +
"-classpath " + CFileUtils.quoteFilePath(junitJarPath + CLASSPATH_DELIMITER + additionalClasspath + CLASSPATH_DELIMITER + javaClientDriverJarPath + CLASSPATH_DELIMITER + testRootPath) + " " +
JUNIT4_RUNNER_CLASS + " ";
} else if (executionFramework.equals("TestNG")) {
framework = TESTNG_FRAMEWORK;
testngJarPath = getStringParamValue("TestNG", "TestNG jar path"); // i.e. Y:/Externals/testng-5.10/testng-5.10-jdk15.jar
interpreter = CFileUtils.quoteFilePath(javaInstallPath + "/bin/" + JAVA_INTERPRETER_EXE) + " " +
"-classpath " + CFileUtils.quoteFilePath(testngJarPath + CLASSPATH_DELIMITER + additionalClasspath + CLASSPATH_DELIMITER + javaClientDriverJarPath + CLASSPATH_DELIMITER + testRootPath) + " " +
TESTNG_RUNNER_CLASS + " ";
}
} catch (CParamParsingException e) {
traceln(LOG_PRIORITY_SEVERE, "parsing error during initialization");
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "Exception during initialize: " + e.getMessage()));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
}
// +------------------------------------+
// | Run the Selenium server
// +------------------------------------+
seleniumServerTraceFile = new File("selenium_server_traces.txt");
if (seleniumServerTraceFile.exists())
seleniumServerTraceFile.delete();
try {
seleniumServerTraceFile.createNewFile();
} catch (IOException e) {
traceln(LOG_PRIORITY_SEVERE, "Could not create file \"selenium_server_traces.txt\"...");
}
// if there is already a selenium server running that's not a problem has 2 server cannot listen on the same port this will fail nicely
seleniumServer = new CRunner("[Selenium Server] ",
CFileUtils.quoteFilePath(javaInstallPath + "/bin/" + JAVA_INTERPRETER_EXE) + " -jar " + CFileUtils.quoteFilePath(seleniumServerJarPath) + " " + seleniumServerOptions,
workingDir);
short result = seleniumServer.requestAction(IRunner.START_PROCESS, IRunner.DO_NOT_WAIT_END_OF_EXECUTION, seleniumServerTraceFile);
if (result == RESULT_SUCCESS) {
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "initialize: selenium server successfully launched!"));
traceln(LOG_PRIORITY_INFO, "selenium server launched successfully");
} else {
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "initialize: couldn't run selenium server! Maybe a server is already running"));
traceln(LOG_PRIORITY_SEVERE, "couldn't run selenium server!");
}
// let the time to the server to initialize (this is done only once per campaign session)
CUtils.sleep(7000);
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}
public CReturnStatus preRun(int testId, String testPath, String testName, Vector attributes, String additionalInfo) {
traceln(LOG_PRIORITY_INFO, "preRun testId=" + testId + " testPath=" + testPath + " [" + testName + "]...");
Vector executionSteps = new Vector();
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}
public CReturnStatus run(int testId, String testPath, String testName, int testcaseIndex, String testcaseName, String additionalInfo) {
traceln(LOG_PRIORITY_INFO, "run testId=" + testId + " testPath=" + testRootPath + "/" + testPath + "/" + testName + " testcaseIndex=" + testcaseIndex + "...");
Vector executionSteps = new Vector();
workingDir = new File(testRootPath); // parent folder of all the test classes
// +------------------------------------+
// | Interpret the script
// +------------------------------------+
File seleniumTraceFile = new File(TRACE_FILE_NAME);
if (seleniumTraceFile.exists())
seleniumTraceFile.delete();
try {
seleniumTraceFile.createNewFile();
} catch (IOException e) {
traceln(LOG_PRIORITY_SEVERE, "Could not create file \"" + TRACE_FILE_NAME + "\"...");
}
// +------------------------------------+
// | Run the JUnit test class
// +------------------------------------+
CRunner seleniumRunner = null;
short result = RESULT_FAILURE;
if (framework == JUNIT_FRAMEWORK) {
seleniumRunner = new CRunner("[" + testId + "] "+ testPath + "." + testName,
interpreter.toString() + " " + testPath + "." + testName,
workingDir);
result = seleniumRunner.requestAction(IRunner.START_PROCESS, IRunner.WAIT_END_OF_EXECUTION, seleniumTraceFile);
} else if (framework == TESTNG_FRAMEWORK) {
seleniumRunner = new CRunner("[" + testId + "] "+ testPath + "." + testName,
interpreter.toString() + " -testclass " + testPath + "." + testName,
workingDir);
result = seleniumRunner.requestAction(IRunner.START_PROCESS, IRunner.WAIT_END_OF_EXECUTION, seleniumTraceFile);
addAttachment(new File(testRootPath + "/test-output/emailable-report.html"));
addAttachment(new File(testRootPath + "/test-output/index.html"));
addAttachment(new File(testRootPath + "/test-output/testng-results.xml"));
} else {
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "Undetermined execution framework"));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
}
// +------------------------------------+
// | Add the output console to the test
// +------------------------------------+
addAttachment(seleniumTraceFile);
if (result == RESULT_FAILURE) {
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "execution process failed"));
// to have the details anyway
if (framework == JUNIT_FRAMEWORK) {
parseJUnitResultFile(executionSteps);
} else if (framework == TESTNG_FRAMEWORK) {
parseTestNGResultFile(executionSteps);
}
return new CReturnStatus(RESULT_FAILURE, executionSteps);
} else {
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "execution process succeeded"));
if (framework == JUNIT_FRAMEWORK) {
return parseJUnitResultFile(executionSteps);
} else if (framework == TESTNG_FRAMEWORK) {
return parseTestNGResultFile(executionSteps);
} else {
return new CReturnStatus(RESULT_FAILURE, executionSteps);
}
}
}
public CReturnStatus postRun(int testId, String testPath, String testName) {
traceln(LOG_PRIORITY_INFO, "postRun testId=" + testId + " testPath=" + testPath + ":" + testName + "...");
Vector executionSteps = new Vector();
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "postRun: succeeded"));
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}
public CReturnStatus terminate() {
traceln(LOG_PRIORITY_INFO, "terminate killing selenium server...");
// +------------------------------------+
// | Run the Selenium server
// +------------------------------------+
seleniumServer.killProcess();
Vector executionSteps = new Vector();
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "Terminate"));
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}
// +--------------------------+
// ¦ Utilities ¦
// +--------------------------+
private CReturnStatus parseJUnitResultFile(Vector executionSteps) {
// parse the result file to get the result and the execution steps
File resultFile = new File(TRACE_FILE_NAME);
if (!resultFile.exists()) {
traceln(LOG_PRIORITY_SEVERE, "Result file not found!");
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "run: result file not found!"));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
} else {
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "run: result file found"));
}
String line, message;
boolean errorDetected = false;
int errorIndex = 1;
try {
FileInputStream fileInputStream = new FileInputStream(resultFile);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
while ((line = bufferedReader.readLine()) != null) {
line = line.trim();
System.out.println(">" + line);
if (line.startsWith("JUnit version ")) {
executionSteps.add(new CExecutionStep(RESULT_UNKNOWN, line));
} else if (line.startsWith("Could not find class")) {
executionSteps.add(new CExecutionStep(RESULT_FAILURE, line));
errorDetected = true;
} else if (line.startsWith("Exception in thread \"main\"")) {
executionSteps.add(new CExecutionStep(RESULT_FAILURE, line));
errorDetected = true;
} else if (line.startsWith("Time: ")) {
executionSteps.add(new CExecutionStep(RESULT_UNKNOWN, line));
} else if (line.startsWith("There was") && line.endsWith("failure:")
|| line.startsWith("There were") && line.endsWith("failures:")) {
executionSteps.add(new CExecutionStep(RESULT_FAILURE, line));
errorDetected = true;
} else if (line.startsWith(errorIndex + ")")) {
errorDetected = true;
message = line.substring((errorIndex + ")").length() + 1, line.length());
String nextLine = bufferedReader.readLine();
if (nextLine != null)
message = message + nextLine;
executionSteps.add(new CExecutionStep(RESULT_FAILURE, message));
errorIndex++;
} else if (line.startsWith("OK ")) {
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, line));
} else if (line.startsWith("Tests run")) {
executionSteps.add(new CExecutionStep(RESULT_UNKNOWN, line));
} else {
//traceln(LOG_PRIORITY_SEVERE, "unknown tag!");
}
}
} catch (Exception e) {
traceln(LOG_PRIORITY_SEVERE, "exception whle parsing the result file: " + e);
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "Exception while parsing the result file: " + e));
errorDetected = true;
}
if (errorDetected) {
return new CReturnStatus(RESULT_FAILURE, executionSteps);
} else {
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}
}
private CReturnStatus parseTestNGResultFile(Vector executionSteps) {
// parse the result file to get the result and the execution steps
File resultFile = new File(testRootPath + "/test-output/testng-results.xml");
if (!resultFile.exists()) {
traceln(LOG_PRIORITY_SEVERE, "Result file not found!");
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "run: result file not found!"));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
} else {
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "run: result file found"));
}
// parse the result file to get the result and the execution steps
Document xmlDocument = CXmlDocumentFactory.createXMLDoc(resultFile);
Node rootXmlNode = xmlDocument.getFirstChild();
int nbSkipped;
int nbFails;
int nbSuccess;
try {
nbSkipped = CXmlDocumentFactory.getNodeIntegerValueFromXPath(rootXmlNode, "count(//test-method[@status='SKIP'])");
nbFails = CXmlDocumentFactory.getNodeIntegerValueFromXPath(rootXmlNode, "count(//test-method[@status='FAIL'])");
nbSuccess = CXmlDocumentFactory.getNodeIntegerValueFromXPath(rootXmlNode, "count(//test-method[@status='PASS'])");
} catch (NumberFormatException e) {
traceln(LOG_PRIORITY_SEVERE, "result file parsing failed !");
return new CReturnStatus(RESULT_FAILURE, executionSteps);
}
short result = RESULT_FAILURE;
if (nbFails == 0 && nbSkipped == 0 && nbSuccess > 0) {
result = RESULT_SUCCESS;
} else if (nbFails == 0 && nbSuccess == 0) { // whatever nbSkipped
result = RESULT_NOT_EXECUTED;
}
NodeList resultNodeList = CXmlDocumentFactory.getNodeObjListFromXPath(rootXmlNode, "//test-method");
for (int j=0; j