/*
+----------------------------------------------------------------------+
| Class: CLauncher |
| |
| Developper: Eric Gavaldo (eric.gavaldo@xqual.com) |
| Jumbo |
| Dag Jensen Rimstad |
| Version: 1.10 |
| License: LGPL (http://www.gnu.org/licenses/lgpl.html) |
+----------------------------------------------------------------------+
*/
package com.xqual.xlauncher.perl;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.xqual.xagent.launcher.CExecutionStep;
import com.xqual.xagent.launcher.CLauncher;
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.IConstantsResults;
import com.xqual.xcommon.type.CParam;
import com.xqual.xcommon.type.CParamParsingException;
import com.xqual.xcommon.utils.CFileUtils;
import com.xqual.xcommon.utils.CUtils;
import com.xqual.xlauncher.CTimeoutListener;
/**
* The CLauncherImpl implementation of ILauncher for Perl.
*/
public class CLauncherImpl extends CLauncher implements IConstantsResults {
// +==============================================================+
// | Attributes |
// +==============================================================+
static final String TRACE_HEADER = "{perl } ";
private String testRootPath;
private int timeout = 600;
private String perlInstallPath;
private String scriptParameters = "";
private File workingDir;
private static final String PERL_INTERPRETER_EXE = CUtils.getExecutableName("perl");
private static final Map statusCodes = new HashMap();
static {
statusCodes.put("Success", RESULT_SUCCESS);
statusCodes.put("Failure", RESULT_FAILURE);
statusCodes.put("Log", RESULT_UNKNOWN);
}
// +==============================================================+
// | Constructors |
// +==============================================================+
public CLauncherImpl() {
super(TRACE_HEADER);
}
// +==============================================================+
// | Methods |
// +==============================================================+
@Override
public CReturnStatus initialize(int sutId, String sutName, String sutVersion) {
setSutDetails(sutId, sutName, sutVersion);
// check the configuration sent by the manager
printConfiguration();
Vector executionSteps = new Vector();
try {
// retrieve the parameters we need
testRootPath = getStringParamValue("General", "Test root path");
timeout = getIntegerParamValue("General", "Asynchronous timeout (in seconds)");
scriptParameters = getStringParamValue("General", "Script parameters");
perlInstallPath = getStringParamValue("Perl", "Perl install path");
} 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);
}
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}
@Override
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);
}
@Override
public CReturnStatus run(int testId, String testPath, String testName, int testcaseId, int testcaseIndex, String testcaseName, Vector params, String additionalInfo) {
traceln(LOG_PRIORITY_INFO, "run testId=" + testId + " testPath=" + testRootPath + "/" + testPath + "/" + testName + " testcaseIndex=" + testcaseIndex + "...");
Vector executionSteps = new Vector();
String scriptParentFolderPath = testRootPath + "/" + testPath + "/";
workingDir = new File(scriptParentFolderPath);
// Remove old log file - if it exists
File perlLogFile = new File(workingDir + "/log.txt");
if (perlLogFile.exists()) {
perlLogFile.delete();
}
// +------------------------------------+
// | Interpret the script
// +------------------------------------+
CRunner perlRunner = new CRunner("[" + testId + "] " + testPath + ":" + testName + "." + testcaseIndex,
CFileUtils.quoteFilePath(perlInstallPath + "/" + PERL_INTERPRETER_EXE) + " " +
CFileUtils.quoteFilePath(testRootPath + "/" + testPath + "/" + testName + ".pl") + " " +
"/debug " +
"/testcaseIndex=" + testcaseIndex +
" " + scriptParameters,
workingDir);
short result = perlRunner.requestAction(IRunner.START_PROCESS, IRunner.DO_NOT_WAIT_END_OF_EXECUTION);
if (result == RESULT_FAILURE) {
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "script interpretation failed"));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
}
// to check if the execution completed correctly, we need to check if the "test_completed.txt" has been created
File testCompletedFile = new File(workingDir + "/test_completed.txt");
short resultTimeout = CTimeoutListener.waitForFile(testCompletedFile, timeout);
// Attach log file even if there was a timeout - it may contain clues to what went wrong...
if (perlLogFile.exists()) {
addAttachment(perlLogFile);
}
if (resultTimeout != RESULT_SUCCESS) {
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "timeout of " + timeout + " seconds to execute the test case expired"));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
}
// file exists, remove it to complete asyncronous handshake
if (!testCompletedFile.delete()) {
executionSteps.add(new CExecutionStep(RESULT_UNKNOWN, "Failed to cleanup test_completed.txt"));
}
return parseResultFile(executionSteps);
}
@Override
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);
}
@Override
public CReturnStatus terminate() {
Vector executionSteps = new Vector();
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "Terminate"));
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}
// +--------------------------+
// ¦ Utilities ¦
// +--------------------------+
private CReturnStatus parseResultFile(Vector executionSteps) {
// parse the result file to get the result and the execution steps
File resultFile = new File(workingDir + "/log.txt");
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;
Pattern statusAndTimestamp = Pattern.compile("^(\\d+.+)\\[(Success|Failure|Log)\\](.*)$");
Pattern statusOnly = Pattern.compile("^\\[(Success|Failure|Log)\\](.*)$");
Pattern statusInBetween = Pattern.compile(".*\\[(Success|Failure|Log)\\].*$");
try {
FileInputStream fileInputStream = new FileInputStream(resultFile);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
Matcher statusAndTimestampMatcher = null;
Matcher statusOnlyMatcher = null;
Matcher statusInBetweenMatcher = null;
while ((line = bufferedReader.readLine()) != null) {
line = line.trim();
// System.out.println(">" + line);
statusAndTimestampMatcher = statusAndTimestamp.matcher(line);
if (statusAndTimestampMatcher.matches()) {
executionSteps.add(new CExecutionStep(statusAndTimestampMatcher.group(1),
statusCodes.get(statusAndTimestampMatcher.group(2)),
statusAndTimestampMatcher.group(3)));
if ("Failure".equals(statusAndTimestampMatcher.group(2))) {
errorDetected = true;
}
continue;
}
statusOnlyMatcher = statusOnly.matcher(line);
if (statusOnlyMatcher.matches()) {
executionSteps.add(new CExecutionStep(statusCodes.get(statusOnlyMatcher.group(1)), statusOnlyMatcher.group(2)));
if ("Failure".equals(statusOnlyMatcher.group(1))) {
errorDetected = true;
}
continue;
}
statusInBetweenMatcher = statusInBetween.matcher(line);
if (statusInBetweenMatcher.matches()) {
executionSteps.add(new CExecutionStep(statusCodes.get(statusInBetweenMatcher.group(1)), line));
if ("Failure".equals(statusInBetweenMatcher.group(1))) {
errorDetected = true;
}
continue;
}
//traceln(LOG_PRIORITY_SEVERE, "unknown tag!");
}
bufferedReader.close();
fileInputStream.close();
} catch (Exception e) {
traceln(LOG_PRIORITY_SEVERE, "exception whle parsing the result file: " + e);
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "Exception whle parsing the result file: " + e));
errorDetected = true;
}
if (errorDetected) {
return new CReturnStatus(RESULT_FAILURE, executionSteps);
} else {
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}
}
}