/* +----------------------------------------------------------------------+ | 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