package qat.parser.qashparser;
// JDK imports
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.net.ConnectException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.swing.JLabel;
import qat.common.Common;
import qat.common.ProtocolConstants;
import qat.common.Utils;
import qat.parser.AgentInstance;
import qat.parser.HtmlPrintStream;
import qat.parser.ParserInterface;
/**
* This file loads a single QAT file, and will attempt to resolve all keywords in this qat file
* file by first including any .INC statements, and their parent statements etc, until all neccesary files
* have been included.
*
* @author webhiker
* @version 2.3, 17 June 1999
*
*/
public class QASHParser extends Object implements ParserInterface {
private static final Logger log = Logger.getAnonymousLogger();
private static String QASHFileName="NOTSET";
private static final char COMMA = ',';
private static final char CONCAT_OPERATOR = '+';
private static final char DEC_OPERATOR = '-';
private static final char SEMICOLON = ';';
private static final char LOGICAL_AND = '&';
private static final char LOGICAL_OR = '|';
private static final char SET_OPERATOR = '=';
private static final char SOFTSET_OPERATOR = '?';
private static final char COMMENT = '#';
private static final char LEFT_PARENTHESIS = '(';
private static final char RIGHT_PARENTHESIS = ')';
private static final char GREATER_THAN = '>';
private static final char LESS_THAN = '<';
private static final char NOT_OPERATOR = '!';
// the following constants represent single character representations of
// operators actually encoded as two characters
private static final char LESS_THAN_EQ = '['; // <=
private static final char GREATER_THAN_EQ = ']'; // >=
private static final char NOT_EQUAL_OPERATOR = '~'; // !=
private static final char EQUALITY_OPERATOR = '@'; // ==
private static final char APPEND_OPERATOR = '*'; // +=
private static final int LOOP_OP = 1000;
private static final int INCLUDE = 2000;
private static final int IF = 3000;
private static final int THEN = 4000;
private static final int ELSE = 5000;
private static final int WHILE = 6000;
private static final int FOR = 7000;
private static final int TO = 8000;
private static final int BY = 9000;
private static final int DO = 10000;
private static final int PRINT = 11000;
private static final int END = 12000;
private static final int SETAGENT = 13000;
private static final int DELAGENT = 14000;
private static final int ZIPSEND = 15000;
private static final int ZIPCLEAN = 16000;
private static final int SETPROP = 17000;
private static final int DELPROP = 18000;
private static final int CMDSTART = 19000;
private static final int AUTOCLEAN_ON = 20000;
private static final int CMDSTOP = 21000;
private static final int CMDSTATUS = 22000;
private static final int CMDGETTRACE = 23000;
private static final int CMDCLEAN = 24000;
private static final int SLEEP = 25000;
private static final int REPORTSTATUS = 26000;
private static final int RANDOM = 27000;
private static final int GETFILE = 28000;
private static final int SENDFILE = 29000;
private static final int CHECKFILE = 30000;
private static final int CHECKFILE_LOCAL = 31000;
private static final int CHECKAGENT = 32000;
private static final int DELFILE_LOCAL = 33000;
private static final int DELFILE = 34000;
private static final int MKDIR = 35000;
private static final int MKDIR_LOCAL = 36000;
private static final int SETSTATIC = 37000;
private static final int DELSTATIC = 38000;
private static final int GETSTATIC = 39000;
private static final int PRINTENV = 40000;
private static final int KILLAGENT = 41000;
private static final int ENDFUNCTION = 42000;
private static final int FUNCTION = 43000;
private static final int CALLFUNCTION = 44000;
private static final int AUTOCLEAN_OFF = 45000;
private static final int ENVTRACECONTAINS= 46000;
private static final int STDOUTCONTAINS = 47000;
private static final int STDERRCONTAINS = 48000;
private static final int GETTRACEPATHS = 49000;
private static final int DAEMONSTART = 50000;
private static final int ZIPCREATE_LOCAL = 51000;
private static Properties staticVariables;
// ---- these are the property names expected in a qash or qinc file
public static final String KEYWORD_TAG = "qat.test.keywords";
public static final String TEST_NAME_TAG = "qat.test.name";
public static final String TEST_AUTHOR_TAG = "qat.test.author";
public static final String TEST_BUGINFO_TAG = "qat.test.buginfo";
public static final String TEST_DESCRIPTION_TAG = "qat.test.description";
public static final String BUG_INFO = "qat.test.buginfo";
/**
* For internal use only.
*/
public static final String INCLUDE_QASH_LIST = "qash.internal.include_list";
public static final String INCLUDE_PROPERTIES_LIST = "qash.internal.properties_list";
public static final String INTERNAL_TRACE_LIST = "qash.internal.trace_list";
private QASHToken currToken;
private List<QASHToken> stack;
private List<List<QASHToken>> loopStack;
private int loopStackCount;
private String fileName;
private Properties properties;
private BufferedReader in;
private StreamTokenizer stream;
private int currQASHStatus;
private boolean evaluating;
private boolean interrupted=false;
private static boolean statusReported=false;
private HtmlPrintStream printStream;
private JLabel parserStatus;
private QASHProperties qashProperties;
static {
staticInit();
}
public QASHParser() {
initParser();
}
/**
* This form of the parser is used for the commandline interface.
*/
public QASHParser(Properties p,
QASHProperties qashProperties,
String testPath,
PrintStream printStream,
boolean evaluating) {
this();
this.qashProperties = qashProperties;
setEvaluationMode(evaluating);
setTestPath(testPath);
setProperties(p);
setPrintStream(printStream,true);
}
/**
* This method sets the path to root of the current project.
*/
public void setProjectRoot(String projectRoot) {
// we don't need this method
}
private static void staticInit() {
staticVariables = new Properties();
}
/**
* This method is called at the beginning of a parser run
* on one or more QASH files.
*/
public void prepare(String newProjectResultsDirectory) {
qashProperties = new QASHProperties();
qashProperties.setProjectResultsDirectory(newProjectResultsDirectory);
}
/**
* This method is called after a parser run on one
* or more QASH files.
*/
public void finish() {
qashProperties.finish();
}
public String[] getSyntaxKeyWords() {
return QASHConstants.getSyntaxKeywords();
}
public void resetVariables() {
// set the internal variable for qash script access
setProperty("qat.qash.filepath",fileName);
setProperty("qat.qash.path",(new File(fileName)).getParent());
}
public void setTestPath(String testFileName) {
// set the name of the file currently being parsed
fileName = testFileName;
// if it's a qash file, remember it.
// This is only done once per root qash, since a
// qash may include other qash files
if ((testFileName.toLowerCase().endsWith(".qash"))&&
(QASHFileName.equals("NOTSET"))) {
QASHFileName = testFileName;
}
}
public PrintStream openPrintStream(String fileName) throws java.io.FileNotFoundException {
return new HtmlPrintStream(new PrintStream(new FileOutputStream(fileName),true),true);
}
public final void setPrintStream(PrintStream printStream, boolean useHtml) {
if (printStream instanceof HtmlPrintStream) {
this.printStream = (HtmlPrintStream)printStream;
}
else {
this.printStream = new HtmlPrintStream(printStream,useHtml);
}
}
public void setProperties(Properties p) {
this.properties = p;
addToIncludeList(fileName);
}
public final void setEvaluationMode(boolean mode) {
evaluating = mode;
}
public final boolean inEvaluationMode() {
return evaluating;
}
private int getTokenID(String token) {
return QASHConstants.getTokenID(token);
}
private int getTokenID(QASHToken token) {
return getTokenID(token.toString());
}
private String getTokenValue(int i) {
return QASHConstants.getTokenValue(i);
}
/**
* Clean up unused variables from this parse specific
* to the root qash file.
*/
private void parseFileClean() {
String KEYWORD_TAG_VALUE = getKeyWordsProperty();
String TEST_NAME_TAG_VALUE = getTestName();
String TEST_AUTHOR_TAG_VALUE = getTestAuthor();
String TEST_DESCRIPTION_TAG_VALUE = getTestDescription();
String BUG_INFO_VALUE = getProperty(BUG_INFO);
String INCLUDE_MISC_LIST_VALUE = getProperty(INCLUDE_QASH_LIST);
String INCLUDE_PROPERTIES_LIST_VALUE = getProperty(INCLUDE_PROPERTIES_LIST);
String INTERNAL_TRACE_LIST_VALUE = getProperty(INTERNAL_TRACE_LIST);
properties.clear();
setProperty(KEYWORD_TAG , KEYWORD_TAG_VALUE);
setProperty(TEST_NAME_TAG , TEST_NAME_TAG_VALUE);
setProperty(TEST_AUTHOR_TAG , TEST_AUTHOR_TAG_VALUE);
setProperty(TEST_DESCRIPTION_TAG , TEST_DESCRIPTION_TAG_VALUE);
setProperty(BUG_INFO , BUG_INFO_VALUE);
setProperty(INCLUDE_QASH_LIST , INCLUDE_MISC_LIST_VALUE);
setProperty(INCLUDE_PROPERTIES_LIST , INCLUDE_PROPERTIES_LIST_VALUE);
setProperty(INTERNAL_TRACE_LIST , INTERNAL_TRACE_LIST_VALUE);
qashProperties.clearFunctions();
QASHFileName = "NOTSET";
}
/**
* This method is the main loop for parsing the QASH file.
* It reads the file token by token, and calls the relevant method for
* each token type.
*/
public synchronized int parseFile() throws Exception {
interrupted=false;
setStatusReported(false);
setStatus(internalParseFile());
// if we are at the end of a parse, we can clear all
// per-test variables here.
parseFileClean();
return getStatus();
}
/**
* This method is the main loop for parsing the QASH file.
* It reads the file token by token, and calls the relevant method for
* each token type.
*/
private synchronized int internalParseFile() throws Exception {
resetVariables();
setStatus(ProtocolConstants.PASSED);
List<QASHToken> leftSide = new ArrayList<QASHToken>();
int tokenId;
try {
in = new BufferedReader(new FileReader(fileName));
stream = new StreamTokenizer(in);
setupSyntax();
resetParser();
while ((!isInterrupted())&&
(getNextToken().ttype != QASHToken.TT_EOF)&&
(!isStatusReported())) {
tokenId = getTokenID(currToken.toString());
switch(tokenId) {
case IF : processIF();
break;
case FOR : processFOR();
break;
case WHILE : processWHILE();
break;
case PRINT : processPRINT();
break;
case INCLUDE : processINCLUDE();
break;
case SETAGENT : processSETAGENT();
break;
case DELAGENT : processDELAGENT();
break;
case ZIPSEND : processZIPSEND();
break;
case ZIPCREATE_LOCAL : processZIPCREATE_LOCAL();
break;
case ZIPCLEAN : processZIPCLEAN();
break;
case SETPROP : processSETPROP();
break;
case DELPROP : processDELPROP();
break;
case CMDSTART : processCMDSTART();
break;
case DAEMONSTART : processDAEMONSTART();
break;
case CMDSTOP : processCMDSTOP();
break;
case CMDSTATUS : processCMDSTATUS();
break;
case CMDGETTRACE : processCMDGETTRACE();
break;
case CMDCLEAN :processCMDCLEAN();
break;
case SLEEP : processSLEEP();
break;
case REPORTSTATUS : processREPORTSTATUS();
break;
case RANDOM : processRANDOM();
break;
case GETFILE : processGETFILE();
break;
case SENDFILE : processSENDFILE();
break;
case CHECKFILE : processCHECKFILE();
break;
case CHECKFILE_LOCAL : processCHECKFILE_LOCAL();
break;
case CHECKAGENT : processCHECKAGENT();
break;
case DELFILE_LOCAL : processDELFILE_LOCAL();
break;
case DELFILE : processDELFILE();
break;
case MKDIR : processMKDIR();
break;
case MKDIR_LOCAL : processMKDIR_LOCAL();
break;
case KILLAGENT : processKILLAGENT();
break;
case FUNCTION : processFUNCTION();
break;
case CALLFUNCTION : processCALLFUNCTION();
break;
case SETSTATIC : processSETSTATIC();
break;
case GETSTATIC : processGETSTATIC();
break;
case DELSTATIC : processDELSTATIC();
break;
case PRINTENV : processPRINTENV();
break;
case AUTOCLEAN_ON : processAUTOCLEAN_ON();
break;
case AUTOCLEAN_OFF : processAUTOCLEAN_OFF();
break;
case ENVTRACECONTAINS : processENVTRACECONTAINS();
break;
case STDOUTCONTAINS : processSTDOUTCONTAINS();
break;
case STDERRCONTAINS : processSTDERRCONTAINS();
break;
case GETTRACEPATHS : processGETTRACEPATHS();
break;
case LOOP_OP : processLOOP_OP();
break;
default :
switch (currToken.ttype) {
case QASHToken.TT_EOL :
case SEMICOLON :
break;
case SET_OPERATOR :
processSET_OPERATOR(leftSide);
break;
case SOFTSET_OPERATOR :
processSOFTSET_OPERATOR(leftSide);
break;
case CONCAT_OPERATOR :
// must be part of a left side expression
leftSide.add(currToken);
break;
case APPEND_OPERATOR :
processAPPEND_OPERATOR(leftSide);
break;
default :
// remembering
leftSide.add(currToken);
}
}
}
in.close();
}
catch (IOException e) {
printError(2,"Couldn't resolve file (1)"+fileName+" :"+e.toString());
setStatus(ProtocolConstants.UNRESOLVED);
}
catch (Throwable e) {
printError(2,"Parser error trapped :"+fileName+" :"+e.toString());
setStatus(ProtocolConstants.UNRESOLVED);
}
if (isInterrupted()) {
if (!isStatusReported()) {
setStatus(ProtocolConstants.UNRESOLVED);
}
}
// report if user forgot to match SETAGENT/DELAGENT calls
if ((qashProperties.getActiveAgentCount()>0)&&
(isStatusReported())) {
printWarning(22,"We still have "+qashProperties.getActiveAgentCount()+" uncleaned agents remaining from "+fileName);
qashProperties.clearActiveAgents();
}
return getStatus();
}
private boolean isInterrupted() {
return interrupted;
}
public void interrupt() {
interrupted = true;
// now call kill for all active agents
if (!inEvaluationMode()) {
AgentInstance agent=null;
for (Enumeration<AgentInstance> agentList = qashProperties.getActiveAgents() ; agentList.hasMoreElements() ;) {
try {
agent = (AgentInstance)agentList.nextElement();
agent.KILLSTARTEDPROCESSES();
}
catch (Exception e) {
printError(3,"Error killing one or more agent processes - recommend restarting agents manually!"+" :"+e.toString());
}
}
}
// clear our Hashtable now
qashProperties.clearActiveAgents();
}
/**
* Initialise all the line number counters etc used to parse a file.
*/
private void initParser() {
currToken = new QASHToken();
setEvaluationMode(true);
stack = new ArrayList<QASHToken>();
loopStack = new ArrayList<List<QASHToken>>();
resetParser();
}
private void resetParser() {
currToken.line = 0;
loopStackCount = -1;
stack.clear();
loopStack.clear();
}
public void setupSyntax() {
stream.resetSyntax();
// indicate EOL is significant
stream.eolIsSignificant(true);
// set the whitespace chars
stream.whitespaceChars(1,32);
// indicate we want to parse numbers
stream.parseNumbers();
// set comments to start with a "#"
stream.commentChar((int)COMMENT);
// set the quote char we want to use
stream.quoteChar((int)QASHToken.TT_STRING);
// set the characters accepted
stream.wordChars('@', '_');
stream.wordChars('a', '~');
// set up the separator characters
stream.ordinaryChar((int)LEFT_PARENTHESIS);
stream.ordinaryChar((int)RIGHT_PARENTHESIS);
stream.ordinaryChar((int)CONCAT_OPERATOR);
stream.ordinaryChar((int)DEC_OPERATOR);
stream.ordinaryChar((int)SET_OPERATOR);
stream.ordinaryChar('!');
stream.ordinaryChar((int)LOGICAL_AND);
stream.ordinaryChar((int)LOGICAL_OR);
stream.ordinaryChar((int)SOFTSET_OPERATOR);
stream.ordinaryChar((int)GREATER_THAN);
stream.ordinaryChar((int)LESS_THAN);
stream.ordinaryChar((int)SEMICOLON);
}
private QASHToken getNextStreamToken() throws IOException {
stream.nextToken();
switch ((char)stream.ttype) {
case QASHToken.TT_NUMBER :
return new QASHToken(stream.nval,QASHToken.TT_NUMBER,stream.lineno());
case COMMENT :
return getNextStreamToken();
case QASHToken.TT_EOL :
return new QASHToken(QASHToken.TT_EOL,QASHToken.TT_EOL,stream.lineno());
case QASHToken.TT_WORD :
return new QASHToken(stream.sval,QASHToken.TT_WORD,stream.lineno());
case QASHToken.TT_STRING :
return new QASHToken(stream.sval,QASHToken.TT_STRING,stream.lineno());
case QASHToken.TT_EOF :
return new QASHToken(QASHToken.TT_EOF,QASHToken.TT_EOF,stream.lineno());
// the next four traps are used to convert double char
// operators into single char representations
case CONCAT_OPERATOR : // +=
if (doubleOp(stream))
return new QASHToken(APPEND_OPERATOR,APPEND_OPERATOR,stream.lineno());
else
return new QASHToken(CONCAT_OPERATOR,CONCAT_OPERATOR,stream.lineno());
case NOT_OPERATOR : // !=
if (doubleOp(stream))
return new QASHToken(NOT_EQUAL_OPERATOR,NOT_EQUAL_OPERATOR,stream.lineno());
else
return new QASHToken(NOT_OPERATOR,NOT_OPERATOR,stream.lineno());
case GREATER_THAN : // >=
if (doubleOp(stream))
return new QASHToken(GREATER_THAN_EQ,GREATER_THAN_EQ,stream.lineno());
else
return new QASHToken(GREATER_THAN,GREATER_THAN,stream.lineno());
case LESS_THAN : // <=
if (doubleOp(stream))
return new QASHToken(LESS_THAN_EQ,LESS_THAN_EQ,stream.lineno());
else
return new QASHToken(LESS_THAN,LESS_THAN,stream.lineno());
case SET_OPERATOR : // ==
if (doubleOp(stream))
return new QASHToken(EQUALITY_OPERATOR,EQUALITY_OPERATOR,stream.lineno());
else
return new QASHToken(SET_OPERATOR,SET_OPERATOR,stream.lineno());
default :
return new QASHToken((char)stream.ttype,(char)stream.ttype,stream.lineno());
}
}
/**
* This method returns true if the next token is an '=', else
* it puts the token back onto the stream.
*/
private boolean doubleOp(StreamTokenizer stream) throws IOException {
if ((char)stream.nextToken()==SET_OPERATOR) {
return true;
}
else {
stream.pushBack();
return false;
}
}
private List<QASHToken> getTokensUntil(char c) throws Exception {
List<QASHToken> result = new ArrayList<QASHToken>();
while ((true)&&
(!isInterrupted())) {
getNextToken();
if (currToken.ttype==c) {
return result;
}
if (currToken.ttype==QASHToken.TT_EOL) {
throw new Exception("Expected \""+c+"\" before EOL");
}
if (currToken.ttype==QASHToken.TT_EOF) {
throw new Exception("Expected \""+c+"\" before EOF");
}
result.add(currToken);
}
return result;
}
/**
* This method reads tokens until ";", "=", EOL or EOF is reached.
*/
private List<QASHToken> getStatements() throws Exception {
List<QASHToken> statement = new ArrayList<QASHToken>();
QASHToken next;
getNextToken();
do {
next = currToken;
switch(currToken.ttype) {
case QASHToken.TT_WORD :
case QASHToken.TT_NUMBER :
case QASHToken.TT_STRING :
case CONCAT_OPERATOR :
case DEC_OPERATOR :
case LEFT_PARENTHESIS :
case RIGHT_PARENTHESIS :
statement.add(next);
break;
case SET_OPERATOR :
case SOFTSET_OPERATOR :
case SEMICOLON :
case QASHToken.TT_EOL :
case QASHToken.TT_EOF :
return statement;
default :
throw new Exception("Unexpected token in statement :"+currToken);
}
getNextToken();
} while (!isInterrupted());
return statement;
}
/**
* This method reads the tokens out of the file.
* Sometimes a small lookahead is used.
* When no more tokens are available, QASHToken.TT_EOF is returned.
*/
private QASHToken getNextToken() throws IOException {
// if the stack is empty, only then read another line
if (stack.size()>0) {
currToken = (QASHToken)stack.remove(0); // remove returns the element removed
}
else {
currToken = getNextStreamToken();
}
return currToken;
}
/**
* This method ensures we maintain a list of all files which were used to resolve this QASH file.
* The list of included files is saved in the property fields QASHParser.INCLUDE_PROPERTIES_LIST
* and QASHParser.INCLUDE_MISC_LIST.
*/
private void addToIncludeList(String fileName) {
// now add this file to the include properties list if it has a ".properties" extension
if (fileName.endsWith(".properties")) {
addToIncludeList(INCLUDE_PROPERTIES_LIST,fileName);
log.info(fileName+"--------------------->"+getProperty(INCLUDE_PROPERTIES_LIST));
}
// now add this file to the include misc list
else {
addToIncludeList(INCLUDE_QASH_LIST,fileName);
log.info(fileName+"--------------------->"+getProperty(INCLUDE_QASH_LIST));
}
}
private void addToIncludeList(String key, String prop) {
String list = getProperty(key,"");
if (list.length()>0) {
if (list.indexOf(prop)<0) {
setProperty(key,list+File.pathSeparator+prop);
}
}
else {
setProperty(key,prop);
}
}
/**
* This method reads a then statement block, and returns a ArrayList containing
* each distinct token.
* Due to the syntax restraints, a statement block is ended by an END or ELSE token.
* These statements can then be re-pushed onto the stack depending on the value of if statements etc.
* The last element of this ArrayList will be the matching ELSE or END.
*/
private List<QASHToken> readThenStatementBlock() {
List<QASHToken> tokens = new ArrayList<QASHToken>();
try {
QASHToken token=null;
int endCount = 1;
int tokenId;
do {
token = getNextToken();
tokenId = getTokenID(token);
if ((tokenId==FOR)||
(tokenId==WHILE)||
(tokenId==IF)) {
endCount++;
}
else {
if (tokenId==END) {
endCount--;
}
if (tokenId==ELSE) {
if (endCount==1) // then this one matches our then
endCount--;
}
}
tokens.add(currToken);
} while ((!isInterrupted())&&
(endCount>0)&&
(currToken.ttype!=QASHToken.TT_EOF));
if (currToken.ttype==QASHToken.TT_EOF)
throw new Exception("The IF statement is missing an END or ELSE keyword");
}
catch (Exception e) {
printError(4,"Statement syntax error "+e.getMessage(),currToken);
}
return tokens;
}
private List<QASHToken> readElseStatementBlock() {
List<QASHToken> tokens = new ArrayList<QASHToken>();
try {
QASHToken token;
int endCount = 1;
int tokenId;
do {
token = getNextToken();
tokenId = getTokenID(token);
if ((tokenId==FOR)||
(tokenId==WHILE)||
(tokenId==IF)) {
endCount++;
}
else {
if (tokenId==END) {
endCount--;
}
}
tokens.add(token);
} while ((!isInterrupted())&&
(endCount>0)&&
(currToken.ttype!=QASHToken.TT_EOF));
if (currToken.ttype==QASHToken.TT_EOF)
throw new Exception("The IF statement is missing an END keyword");
}
catch (Exception e) {
printError(5,"Statement syntax error"+e.getMessage(),currToken);
}
return tokens;
}
/**
* Process a line containing an INCLUDE statement.
*/
private void processINCLUDE() {
try {
QASHToken includeFileToken = resolveExpression(getStatements());
String includeFile = includeFileToken.toString();
setStatusText(QASHConstants.getTokenValue(INCLUDE),includeFile.toString());
// check if it exists
File f = new File(includeFile);
if (!f.exists()) {
throw new Exception("Include file not found");
}
// check if it's a .properties include or a .qinc/other type of file
if (includeFile.toLowerCase().indexOf(Common.PROPERTIES_EXTENSION)>0) {
// load the properties file, possibly using cached version
// if we requested it previously
Properties newProperties = qashProperties.getProperties(includeFile);
properties = Utils.mergeProperties(properties,newProperties);
}
else {
QASHParser childParser = new QASHParser(properties, qashProperties, includeFile, printStream, inEvaluationMode());
childParser.setStatusLabel(parserStatus);
int includeStatus = childParser.internalParseFile();
properties = childParser.getProperties();
if (includeStatus!=ProtocolConstants.PASSED) {
if (getStatus() != ProtocolConstants.UNRESOLVED) { // unresolved always overrides any test result
setStatus(includeStatus);
setStatusReported(true);
}
}
}
addToIncludeList(includeFile);
}
catch (Exception e) {
printError(INCLUDE,"Syntax or file error in include statement ("+e.getMessage()+") :",currToken);
}
finally {
resetVariables();
}
}
// /**
// * This method reads an expression of the form (.....) and will
// * not replace any variable reference by their actual values. It may still contain
// * append ops and parenthesis, so ideally need to call resolveExpression.
// */
// private ArrayList readExpression() throws Exception {
// expectLeftParenthesis();
// ArrayList expression = new ArrayList();
// int lcount=0,rcount=0;
// while (!isInterrupted()) {
// switch (currToken.ttype) {
// case QASHToken.TT_WORD :
// expression.add(currToken);
// break;
// case LEFT_PARENTHESIS :
// lcount++;
// expression.add(currToken);
// break;
// case RIGHT_PARENTHESIS :
// rcount++;
// expression.add(currToken);
// break;
// case QASHToken.TT_EOF :
// return expression;
// default :expression.add(currToken);
// }
// if (lcount==rcount)
// break;
// getNextToken();
// }
// return expression;
// }
/**
* This method reads a boolean expression of the form (.....) and will
* replace any variable reference by their actual values. It may still contain
* append ops and parenthesis, so ideally need to call resolveExpression.
*/
private List<QASHToken> readBooleanExpression() throws Exception {
return readExpression(true, true);
} /**
* Same as above method, however will not replace variable names by values.
* This method reads a boolean expression of the form (.....).
* If replace is true, it will replace any variable references by their actual values.
* It may still contain append ops and parenthesis,
* so ideally need to call resolveExpression.
* If enforce is true, any unknown variable will generate an exception.
*/
private List<QASHToken> readExpression(boolean replace, boolean enforce) throws Exception {
expectLeftParenthesis();
List<QASHToken> expression = new ArrayList<QASHToken>();
int lcount=0,rcount=0;
while (!isInterrupted()) {
switch (currToken.ttype) {
case QASHToken.TT_WORD :
if (enforce) {
if (getToken(currToken.toString())==null) {
throw new Exception("Unidentified identifier "+currToken.toString());
}
}
if (replace)
expression.add(getToken(currToken.toString()));
else
expression.add(currToken);
break;
case LEFT_PARENTHESIS :
lcount++;
expression.add(currToken);
break;
case RIGHT_PARENTHESIS :
rcount++;
expression.add(currToken);
break;
case QASHToken.TT_EOF :
return expression;
default :expression.add(currToken);
}
if (lcount==rcount)
break;
getNextToken();
}
return expression;
}
/**
* Process a line containing an IF statement.
*/
private void processIF() {
int ifLineNumber = currToken.line;
try {
List<QASHToken> expression = readBooleanExpression();
// discard the THEN statement
do {
getNextToken();
} while ((currToken.ttype!=QASHToken.TT_EOF)&&
(!isInterrupted())&&
(currToken.ttype!=QASHToken.TT_WORD));
if (!currToken.toString().equals(getTokenValue(THEN)))
throw new Exception("Expected \"THEN\" statement instead of \""+currToken+"\"");
List<QASHToken> thenStatements = readThenStatementBlock();
// if there is an ELSE, read it's block
List<QASHToken> elseStatements;
if (getTokenID((QASHToken)thenStatements.get(thenStatements.size()-1))==ELSE) {
elseStatements = readElseStatementBlock();
elseStatements.remove(elseStatements.size()-1);// remove the END token
}
else {
elseStatements = new ArrayList<QASHToken>();
}
thenStatements.remove(thenStatements.size()-1);// remove the ELSE or END token
if (evaluateBooleanExpression(expression)) {
pushOntoStack(thenStatements);
}
else {
pushOntoStack(elseStatements);
}
}
catch (Exception e) {
printError(IF,"Syntax problem with IF statement ("+e.getMessage()+")",ifLineNumber);
}
}
/**
* This method has the effect of push the statements in this vector back
* onto out stack for processing - used to re-ahead in statement blocks.
*/
private void pushOntoStack(List<QASHToken> v) {
for (int i = 0; i < v.size(); i++) {
stack.add(0+i,v.get(i));
}
}
/**
* Process a line containing a WHILE statement.
*/
private void processWHILE() {
int whileLineNumber = currToken.line;
try { // HERE IS THE ERROR - the readBooleanExpression replaces variables by their value.
// write a new method which keeps the variables in place so
// when we create a LOOP_OP it will keep getting updated
List<QASHToken> expression = readExpression(false,true); // throw away ")"
getNextToken();
if (!currToken.toString().equals(getTokenValue(DO)))
throw new Exception("Expected DO keyword instead of "+currToken);
// now read until matching END statement
List<QASHToken> tokens = new ArrayList<QASHToken>();
QASHToken token;
int tokenId;
int endCount = 1;
do {
token = getNextToken();
tokenId = getTokenID(token);
if ((tokenId==FOR)||
(tokenId==WHILE)||
(tokenId==IF)) {
endCount++;
}
else {
if (tokenId==END) {
endCount--;
}
}
tokens.add(token);
} while ((!isInterrupted())&&
(endCount>0)&&
(currToken.ttype!=QASHToken.TT_EOF));
// check the expression - if it's false we can dump all the code and skip to next op
if (evaluateBooleanExpression(expression)) {
// remove the END statement
tokens.remove(tokens.size()-1);
// add the special loop operator
tokens.add(new QASHToken(getTokenValue(LOOP_OP),QASHToken.TT_WORD,0));
// add the loop type
tokens.add(new QASHToken(getTokenValue(WHILE),QASHToken.TT_WORD,0));
// add the condition expression
for (int i = 0; i < expression.size(); i++)
tokens.add((QASHToken)expression.get(i));
// add the index into the loop stack
loopStackCount++;
tokens.add(new QASHToken(Integer.toString(loopStackCount),QASHToken.TT_WORD,0));
// now add this while block onto our loop Stack
loopStack.add(tokens);
pushOntoStack(tokens);
}
}
catch (Exception e) {
printError(WHILE,"Syntax problem in WHILE loop :"+e.getMessage(),whileLineNumber);
}
}
/**
* This indicates we are currently in a loop. We read an expression, and if it's true,
* repush the loopStack[loopStackIndex] set of tokens onto the main program stack.
* If the expression evaluates to false, we can delete this set of tokens from the loopStack.
*/
private void processLOOP_OP() {
int loopLineNumber = currToken.line;
try {
QASHToken loopType = getNextToken();
if (loopType.toString().equals(getTokenValue(FOR))) {
QASHToken variable = getNextToken();
getNextToken(); // should be the APPEND_OPERATOR +=
QASHToken incAmount = getNextToken();
setProperty(variable.toString(),
Integer.toString(Integer.parseInt(getToken(variable.toString()).toString())+
Integer.parseInt(incAmount.toString())));
}
List<QASHToken> expression = readBooleanExpression();
int loopExpressionLineNumber = currToken.line;
int loopStackIndex = (new Integer(getNextToken().toString())).intValue();
List<QASHToken> loopArray;
int value;
currToken.line = loopExpressionLineNumber;
if (evaluateBooleanExpression(expression)) {
pushOntoStack(loopStack.get(loopStackIndex));
}
else {
// finished with this loop, so discard it's ArrayList
// need to decrement all the stack pointers after this one
for (int i = loopStackIndex; i < loopStack.size(); i++) {
loopArray = loopStack.get(i);
value = new Integer(((QASHToken)loopArray.get(loopArray.size()-1)).toString()).intValue()-1;
loopArray.set(loopArray.size()-1,new QASHToken(new Integer(value).toString(),QASHToken.TT_WORD,0));
}
loopStack.remove(loopStackIndex);
loopStackCount--;
}
}
catch (Exception e) {
printError(LOOP_OP,"Internal error occurred during loop processing :"+e.getMessage(),loopLineNumber);
}
}
/**
* Process a line containing a PRINT statement.
*/
private void processPRINT() {
try {
setStatusText(currToken.toString());
QASHToken tokenToPrint = resolveExpression(getStatements());
printStream.println(HtmlPrintStream.GREEN,tokenToPrint.toString());
}
catch (Exception ex) {
printError(PRINT,"Print syntax incorrect :"+ex.getMessage(),currToken);
}
}
/**
* Process a line containing a FOR statement.
*/
private void processFOR() {
int forLineNumber = currToken.line;
try {
QASHToken leftSide = getNextToken();
getNextToken();
if (currToken.ttype!=(int)SET_OPERATOR)
throw new Exception("Expected = operator but found "+currToken.toString());
QASHToken rightSide = getNextToken();
getNextToken();
if (!currToken.toString().equals(getTokenValue(TO)))
throw new Exception("Expected TO keyword but found "+currToken.toString());
QASHToken upperLimitString = getNextToken(); QASHToken doString = getNextToken();
// check if we have a BY keyword
QASHToken incAmount = new QASHToken("1",QASHToken.TT_NUMBER,currToken.line);
if (doString.toString().indexOf(getTokenValue(BY))>=0) {
incAmount = getNextToken();
doString = getNextToken();
} // check if right side is a constant or a variable
try {
Integer.parseInt(rightSide.toString());
setProperty(leftSide.toString(),rightSide.toString());
}
catch (NumberFormatException ex) {
// must be a variable, so resolve it
setProperty(leftSide.toString(),resolveExpression(rightSide).toString());
}
QASHToken loopVariable = leftSide;
// read until matching END statement
List<QASHToken> tokens = new ArrayList<QASHToken>();
QASHToken token;
int tokenId;
int endCount = 1;
do {
token = getNextToken();
tokenId=getTokenID(token);
if ((tokenId==FOR)||
(tokenId==WHILE)||
(tokenId==IF)) {
endCount++;
}
else {
if (tokenId==END) {
endCount--;
}
}
tokens.add(token);
} while ((!isInterrupted())&&
(endCount>0)&&
(currToken.ttype!=QASHToken.TT_EOF));
// check the expression - if it's false we can dump all the code and skip to next op
List<QASHToken> expression = new ArrayList<QASHToken>();
expression.add(new QASHToken(LEFT_PARENTHESIS,LEFT_PARENTHESIS,currToken.line));
expression.add(loopVariable);
expression.add(new QASHToken(LESS_THAN_EQ,LESS_THAN_EQ,currToken.line));
expression.add(upperLimitString);
expression.add(new QASHToken(RIGHT_PARENTHESIS,RIGHT_PARENTHESIS,currToken.line));
if (evaluateBooleanExpression(expression)) {
// remove the END statement
tokens.remove(tokens.size()-1);
// add the special loop operator
tokens.add(new QASHToken(getTokenValue(LOOP_OP),QASHToken.TT_WORD,0));
// add the loop type
tokens.add(new QASHToken(getTokenValue(FOR),QASHToken.TT_WORD,0));
// add the increment statement
tokens.add(loopVariable);
tokens.add(new QASHToken(APPEND_OPERATOR,APPEND_OPERATOR,0));
tokens.add(incAmount);
// add the condition expression
tokens.add(new QASHToken(LEFT_PARENTHESIS,LEFT_PARENTHESIS,0));
tokens.add(loopVariable);
tokens.add(new QASHToken(LESS_THAN_EQ,LESS_THAN_EQ,stream.lineno()));
tokens.add(upperLimitString);
tokens.add(new QASHToken(RIGHT_PARENTHESIS,RIGHT_PARENTHESIS,0)); // add the index into the loop stack
loopStackCount++;
tokens.add(new QASHToken(Integer.toString(loopStackCount),QASHToken.TT_WORD,0));
// now add this while block onto our loop Stack
loopStack.add(tokens);
pushOntoStack(tokens);
}
}
catch (Exception e) {
printError(FOR,"Syntax problem in FOR loop :"+e.getMessage(),forLineNumber);
}
}
/**
* Process an SET command.
*/
private void processSET_OPERATOR(List<QASHToken> leftSideExpr) {
try {
QASHToken leftSide = resolveName(leftSideExpr);
leftSideExpr.clear();
List<QASHToken> rightSideExpr = getStatements();
QASHToken rightSide = resolveExpression(rightSideExpr);
setProperty(leftSide.toString(),rightSide.toString());
}
catch (Exception e) {
printError(SET_OPERATOR,"Problem processing set statement command ("+e.toString()+") :",currToken);
}
}
/**
* Process an APPEND command of the form "simplestatement += complexstatement".
*/
private void processAPPEND_OPERATOR(List<QASHToken> leftSideExpr) {
try {
QASHToken leftSide = resolveName(leftSideExpr);
QASHToken leftSideVal = resolveExpression(leftSideExpr);
leftSideExpr.clear();
QASHToken rightSide = resolveExpression(getStatements());
leftSideVal.append(rightSide);
setProperty(leftSide,leftSideVal);
}
catch (Exception e) {
printError(SET_OPERATOR,"Problem processing append statement ("+e.toString()+") :",currToken);
}
}
/**
* Same as a set command, but only applied if the variable is not already defined.
*/
private void processSOFTSET_OPERATOR(List<QASHToken> leftSideExpr) {
try {
QASHToken leftSideName = resolveName(leftSideExpr);
QASHToken rightSide = resolveExpression(getStatements());
leftSideExpr.clear();
if (getToken(leftSideName)==null) {
setProperty(leftSideName,rightSide);
}
}
catch (Exception e) {
printError(SOFTSET_OPERATOR,"Problem processing soft set statement command ("+e.toString()+") :"+leftSideExpr,currToken);
}
}
/**
* This command creates an agent instance used to send,recieve,execute commands.
* SYNTAX : SETAGENT(agentID, agentName, agentPort, agentWorkDirectory)
* The identifier to use this agent instance is returned in the agentID property.
*/
private void processSETAGENT() {
try {
expectLeftParenthesis();
List<QASHToken> expression = getTokensUntil(COMMA);
QASHToken agentID = resolveName(expression);
expression = getTokensUntil(COMMA);
QASHToken agentName = resolveExpression(expression);
expression = getTokensUntil(COMMA);
QASHToken agentPort = resolveExpression(expression);
expression = getTokensUntil(RIGHT_PARENTHESIS);
QASHToken agentWorkDir = resolveExpression(expression);
setStatusText(QASHConstants.getTokenValue(SETAGENT),agentID.toString());
// check that this agentID is unused
if (getToken(agentID)!=null) {
throw new Exception("Identifier already exists :"+agentName.toString());
}
int uniqueID = Utils.getUniqueID();
AgentInstance agentInstance = new AgentInstance(agentName.toString(),
new Integer(agentPort.toString()).intValue(),
agentWorkDir.toString(),
inEvaluationMode());
qashProperties.addActiveAgent(new Integer(uniqueID),agentInstance);
// set the agentID property to reflect the agent ID which was allocated
setProperty(agentID.toString(),Integer.toString(uniqueID));
}
catch (Exception e) {
printError(SETAGENT,"Problem processing SETAGENT command ("+e.toString()+") :",currToken);
}
}
/**
* This command removes a previously defined agent, as well as deleting that agents work directory.
* Any files in the work directory, and their subdirectories will be removed.
* SYNTAX : DELAGENT(agentID)
*/
private void processDELAGENT() {
try {
expectLeftParenthesis();
QASHToken agentIDName = resolveName(getTokensUntil(RIGHT_PARENTHESIS));
QASHToken agentID = resolveExpression(agentIDName); setStatusText(QASHConstants.getTokenValue(DELAGENT),agentIDName.toString());
AgentInstance agentInstance = (AgentInstance)qashProperties.removeActiveAgent(new Integer(agentID.toString())); // remove also returns the object it deleted
if (agentInstance==null)
throw new Exception("Unknown agentID");
try {
agentInstance.DELAGENT();
}
catch (Exception ex) {
printError(DELAGENT,"Error cleaning up agent ("+ex.toString()+") :",currToken);
}
finally {
// unset this agentID property
removeProperty(agentIDName);
}
}
catch (Exception e) {
printError(DELAGENT,"Problem in DELAGENT command ("+e.toString()+") :",currToken);
}
}
/**
* This command sends a zip file to the specified agent to be unzipped.
* SYNTAX : ZIPSEND(agentID, zipID, zipFile)
*/
private void processZIPSEND() {
try {
expectLeftParenthesis();
QASHToken agentID = resolveExpression(getTokensUntil(COMMA));
QASHToken zipID = resolveName(getTokensUntil(COMMA));
QASHToken zipFile = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
setStatusText(QASHConstants.getTokenValue(ZIPSEND),zipID.toString());
// check that this zip id is unused
if (getToken(zipID)!=null) {
throw new Exception("ZIP Identifier already exists :"+zipID.toString()+SET_OPERATOR+getToken(zipID).toString());
}
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID");
// send the zip file, and retrieve the associated zip ID
try {
setProperty(zipID.toString(),agentInstance.ZIPSEND(zipFile.toString()));
}
catch (Exception ex) {
printError(ZIPSEND,"Problem sending zip file to agent ("+ex.toString()+") :",currToken);
}
}
catch (Exception e) {
printError(ZIPSEND,"Problem processing ZIPSEND command ("+e.toString()+") :",currToken);
}
}
/**
* This command commands the agent to delete the previously sent zip file with ID
* agentID and all the files it unzipped.
* SYNTAX : ZIPCLEAN(zipID)
*/
private void processZIPCLEAN() {
try {
expectLeftParenthesis();
List<QASHToken> zipIDVariable = getTokensUntil(RIGHT_PARENTHESIS);
QASHToken zipIDVar = resolveName(zipIDVariable);
QASHToken zipID = resolveExpression(zipIDVar);
setStatusText(QASHConstants.getTokenValue(ZIPCLEAN),zipIDVar.toString());
AgentInstance agentInstance = getAgentForZip(zipID.toString());
if (agentInstance==null)
throw new Exception("Unknown zipID "+zipIDVar);
agentInstance.ZIPCLEAN(zipID.toString());
removeProperty(zipIDVar.toString());
}
catch (Exception e) {
printError(ZIPCLEAN,"Problem processing ZIPCLEAN command ("+e.toString()+") :",currToken);
}
}
/**
* This command creates a zip file called zipFileName, containing the contents of the
* specified dirName. This is done on the maching running the harness only.
* SYNTAX : ZIPCREATE_LOCAL(zipFileName, dirName)
*/
private void processZIPCREATE_LOCAL() {
try {
expectLeftParenthesis();
QASHToken zipFileName = resolveExpression(getTokensUntil(COMMA));
QASHToken dirName = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
setStatusText(QASHConstants.getTokenValue(ZIPCREATE_LOCAL),zipFileName.toString());
File cpFile = new File (dirName.toString());
if (!cpFile.isFile() && !cpFile.isDirectory() ) {
printError(ZIPSEND,"Problem processing ZIPCREATE_LOCAL command ("+dirName+" does not exist) :",currToken);
return;
}
FileOutputStream fos = new FileOutputStream(zipFileName.toString());
ZipOutputStream cpZipOutputStream = new ZipOutputStream(fos);
cpZipOutputStream.setLevel(9);
zipFiles(cpZipOutputStream, cpFile, dirName.toString());
cpZipOutputStream.finish();
cpZipOutputStream.close();
}
catch (Exception e) {
printError(ZIPSEND,"Problem processing ZIPCREATE_LOCAL command ("+e.toString()+") :",currToken);
}
}
private void zipFiles(ZipOutputStream cpZipOutputStream, File cpFile, String offset) {
int byteCount;
final int DATA_BLOCK_SIZE = 2048;
FileInputStream cpFileInputStream;
if (cpFile.isDirectory()) {
File [] fList = cpFile.listFiles() ;
for (int i=0; i< fList.length; i++){
zipFiles(cpZipOutputStream, fList[i], offset) ;
}
}
else {
try {
String strAbsPath = cpFile.getPath();
String strZipEntryName = strAbsPath.substring(offset.length()+1, strAbsPath.length());
cpFileInputStream = new FileInputStream (cpFile) ;
ZipEntry cpZipEntry = new ZipEntry(strZipEntryName);
cpZipOutputStream.putNextEntry(cpZipEntry );
byte[] b = new byte[DATA_BLOCK_SIZE];
while ( (byteCount = cpFileInputStream.read(b, 0, DATA_BLOCK_SIZE)) != -1)
{
cpZipOutputStream.write(b, 0, byteCount);
}
cpZipOutputStream.closeEntry() ;
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Set a property on an agent which will be visible to all following CMDSTART calls on that agent.
* SYNTAX : SETPROP(AGENT_ID, KEY, VALUE) or SETPROP(AGENT_ID, KEY)
*/
private void processSETPROP() {
QASHToken key=null, value=null;
try {
expectLeftParenthesis();
QASHToken agentID = resolveExpression(getTokensUntil(COMMA));
List<QASHToken> expression = getTokensUntil(RIGHT_PARENTHESIS);
int commaIndex;
if ((commaIndex=indexOf(expression,COMMA))>=0) {
// form 1 of the allowed syntax
List<QASHToken> keyList, valueList;
keyList = copyRange(expression,0,commaIndex);
valueList = copyRange(expression,commaIndex+1,expression.size());
key = resolveExpression(keyList);
value = resolveExpression(valueList);
}
else {
// form 2 of the allowed syntax
key = resolveName(expression);
value = resolveExpression(key);
}
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID");
agentInstance.SETPROP(key.toString(),value.toString());
}
catch (Exception e) {
printError(SETPROP,"Problem processing SETPROP command ("+e.toString()+") :",currToken);
}
}
/**
* Deletes a property on an agent which was previously set by a call to SETPROP
* SYNTAX : DELPROPPROP(AGENT_ID, KEY)
*/
private void processDELPROP() {
try {
expectLeftParenthesis();
QASHToken agentIDName = resolveName(getTokensUntil(COMMA));
QASHToken key = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
QASHToken agentID = resolveExpression(agentIDName);
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID");
agentInstance.DELPROP(key.toString(),null);
}
catch (Exception e) {
printError(DELPROP,"Problem processing DELPROP command ("+e.toString()+") :",currToken);
}
}
/**
* Excutes a command on a pre-activated agent.
* SYNTAX: CMDSTART(agentID, processID, command, timeout) or CMDSTART(agentID, processID, command)
* Warning :The second form will use a default timeout value of infinity. A call to CMDSTATUS
* will then only return if the executed process exits normally.
*/
private void processCMDSTART() {
QASHToken command=null, timeout=null;
try {
expectLeftParenthesis();
QASHToken agentID = resolveExpression(getTokensUntil(COMMA));
QASHToken processID = resolveName(getTokensUntil(COMMA));
setStatusText(QASHConstants.getTokenValue(CMDSTART),processID.toString());
// check that this process id is unused
if (getToken(processID)!=null) {
throw new Exception("processID Identifier already exists :"+processID+SET_OPERATOR+getToken(processID).toString());
}
List<QASHToken> expression = getTokensUntil(RIGHT_PARENTHESIS);
int commaIndex;
if ((commaIndex=indexOf(expression,COMMA))>=0) {
// form 1 of the allowed syntax
List<QASHToken> commandList, timeoutList;
commandList = copyRange(expression,0,commaIndex);
timeoutList = copyRange(expression,commaIndex+1,expression.size());
command = resolveExpression(commandList);
timeout = resolveExpression(timeoutList);
}
else {
// form 2 of the allowed syntax
command = resolveExpression(expression);
timeout = new QASHToken("0",QASHToken.TT_NUMBER,command.line);
}
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID"); setProperty(processID.toString(),agentInstance.CMDSTART(strToArray(command.toString()), timeout.toString()));
}
catch (Exception e) {
printError(CMDSTART,"Problem processing CMDSTART command ("+e.toString()+") :",currToken);
}
}
/**
* Converts a string of form "cmd arg1 arg2 arg3" into an array [cmd arg1, arg2, arg3]
*/
private static String[] strToArray(String command) {
try {
int quoteChar = '\"';
List<String> args = new ArrayList<String>();
StreamTokenizer stream = new StreamTokenizer(new StringReader(command));
stream.resetSyntax();
// set the characters accepted
stream.wordChars(33, 126);
stream.whitespaceChars(1,32);
stream.quoteChar(quoteChar);
while (stream.nextToken()!=StreamTokenizer.TT_EOF) {
// if (stream.ttype==quoteChar) {
// args.add('\"'+stream.sval+'\"');
// }
// else {
args.add(stream.sval);
// }
}
String strArgs[] = new String[args.size()];
for (int i = 0; i < strArgs.length; i++) {
strArgs[i] = (String)args.get(i);
}
return strArgs;
}
catch(Exception ex) {
ex.printStackTrace();
return new String[0];
}
} /**
* Cleans the stdout and stderr files created by the process.
* SYNTAX: CMDSTOP(processID) or CMDSTOP(processID, status)
*/
private void processCMDSTOP() {
try {
QASHToken processIDName;
QASHToken processID;
QASHToken statusID=null;
expectLeftParenthesis();
List<QASHToken> expression = getTokensUntil(RIGHT_PARENTHESIS);
int commaIndex;
if ((commaIndex=indexOf(expression,COMMA))>=0) {
// form 2 of the allowed syntax
List<QASHToken> processIDList, statusIdList;
processIDList = copyRange(expression,0,commaIndex);
statusIdList = copyRange(expression,commaIndex+1,expression.size());
processIDName = resolveName(processIDList);
statusID = resolveName(statusIdList);
}
else {
// form 1 of the allowed syntax
processIDName = resolveName(expression);
}
processID = getToken(processIDName);
setStatusText(QASHConstants.getTokenValue(CMDSTOP),processIDName.toString());
AgentInstance agentInstance = getAgentRunningProcess(processID.toString());
if (agentInstance==null)
throw new Exception("Unknown processID");
if (statusID!=null) {
//form 2
setProperty(statusID.toString(),agentInstance.CMDSTOP(processID.toString()));
}
else {
// form 1
agentInstance.CMDSTOP(processID.toString());
}
}
catch (Exception e) {
printError(CMDSTOP,"Problem processing CMDSTOP command ("+e.toString()+") :",currToken);
}
}
/**
* Returns the status of the executed process..
* SYNTAX: CMDSTATUS(processID, statusValue)
* Warning : If the timeout was not set in the CMDSTART, this method will block until
* the executed process exits.
*/
private void processCMDSTATUS() {
try {
expectLeftParenthesis();
QASHToken processIDName = resolveName( getTokensUntil(COMMA));
QASHToken processID = getToken(processIDName);
QASHToken processStatus = resolveName(getTokensUntil(RIGHT_PARENTHESIS));
setStatusText(QASHConstants.getTokenValue(CMDSTATUS),processIDName.toString());
AgentInstance agentInstance = getAgentRunningProcess(processID.toString());
if (agentInstance==null)
throw new Exception("Unknown processID");
String statusCode = agentInstance.CMDSTATUS(processID.toString());
setProperty(processStatus.toString(),statusCode);
// now print out a message if the status was timed out
int value = Integer.parseInt(statusCode);
if (value == qat.agent.ExecProcess.TIMEDOUT_STATE) {
printDebug("The command "+processIDName+" timed out!");
}
else {
if (value < 0) {
printDebug("The command "+processIDName.toString()+" failed!");
}
else {
printDebug("The command "+processIDName.toString()+" exited normally");
}
}
}
catch (Exception e) {
printError(CMDSTATUS,"Problem processing CMDSTATUS command ("+e.toString()+") :",currToken);
}
}
/**
* Cleans the stdout and stderr files created by the process.
* SYNTAX: CMDGETTRACE(processID)
* Warning : Do not call this method until after the output has been retrieved.
*/
private void processCMDGETTRACE() {
try {
List<QASHToken> expression = readExpression(false, true);
// log.info("---------------------");
// log.info("expression>>>>>>>>>"+expression);
QASHToken processIDName = resolveName(expression);
//log.info("processIDName>>>>>>>>>"+processIDName);
QASHToken processID = getToken(processIDName);
//log.info("processID>>>>>>>>>"+processID);
//log.info("---------------------");
setStatusText(QASHConstants.getTokenValue(CMDGETTRACE),processIDName.toString());
AgentInstance agentInstance = getAgentRunningProcess(processID.toString());
if (agentInstance==null)
throw new Exception("Unknown processID");
agentInstance.CMDGETTRACE(processID.toString(),
qashProperties.getProjectResultsDirectory()+File.separator+
Common.getUniqueTestIdentifier(QASHFileName)+"_"+processIDName.toString());
addToIncludeList(INTERNAL_TRACE_LIST,processIDName.toString());
}
catch (Exception e) {
e.printStackTrace();
printError(CMDGETTRACE,"Problem processing CMDGETTRACE command ("+e.toString()+") :",currToken);
}
}
/**
* Excutes a daemon command on a pre-activated agent.
* SYNTAX: DAEMONSTART(agentID, command)
* This function is used for launching daemons, since we typically
* never need to kill these processes.
* Apart from parsing errors, no errors about the status of the daemon, nor it's traces
* may be obtained.
*
*/
private void processDAEMONSTART() {
try {
expectLeftParenthesis();
QASHToken agentID = resolveExpression(getTokensUntil(COMMA));
List<QASHToken> expression = getTokensUntil(RIGHT_PARENTHESIS);
QASHToken command=null;
command = resolveExpression(expression);
setStatusText(QASHConstants.getTokenValue(DAEMONSTART),command.toString());
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID");
agentInstance.DAEMONSTART(strToArray(command.toString()));
}
catch (Exception e) {
printError(DAEMONSTART,"Problem processing DAEMONSTART command ("+e.toString()+") :",currToken);
}
}
/**
* Returns 0 if the commandId contains the specified String in the stdout trace,
* else returns 1. This command should only be called if the trace
* was retrieved by a call to CMDGETTRACE(...)
* SYNTAX: ENVTRACECONTAINS(processID, result, matchstring)
* Warning : Do not call this method until after the output has been retrieved.
*/
private void processENVTRACECONTAINS() {
try {
expectLeftParenthesis();
QASHToken processIDName = resolveName(getTokensUntil(COMMA));
QASHToken result = resolveName(getTokensUntil(COMMA));
QASHToken grepString = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
QASHToken processID = getToken(processIDName);
setStatusText(QASHConstants.getTokenValue(ENVTRACECONTAINS),grepString.toString()); AgentInstance agentInstance = getAgentRunningProcess(processID.toString());
if (agentInstance==null)
throw new Exception("Unknown processID");
String resultCode;
resultCode = agentInstance.ENVTRACECONTAINS(processID.toString(),
qashProperties.getProjectResultsDirectory()+File.separator+
Common.getUniqueTestIdentifier(QASHFileName)+"_"+processIDName.toString(),
grepString.toString());
setProperty(result.toString(),resultCode);
}
catch (Exception e) {
printError(ENVTRACECONTAINS,"Problem processing ENVTRACECONTAINS command ("+e.toString()+") :",currToken);
}
}
/**
* Returns 0 if the commandId contains the specified String in the stdout trace,
* else returns 1. This command should only be called if the trace
* was retrieved by a call to CMDGETTRACE(...)
* SYNTAX: STDOUTCONTAINS(processID, result, matchstring)
* Warning : Do not call this method until after the output has been retrieved.
*/
private void processSTDOUTCONTAINS() {
try {
expectLeftParenthesis();
QASHToken processIDName = resolveName(getTokensUntil(COMMA));
QASHToken result = resolveName(getTokensUntil(COMMA));
QASHToken grepString = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
QASHToken processID = getToken(processIDName);
setStatusText(QASHConstants.getTokenValue(STDOUTCONTAINS),grepString.toString());
if (processIDName==null)
throw new Exception("Invalid process ID");
AgentInstance agentInstance = getAgentRunningProcess(processID.toString());
if (agentInstance==null)
throw new Exception("Unknown processID");
String resultCode;
resultCode = agentInstance.STDOUTCONTAINS(processID.toString(),
qashProperties.getProjectResultsDirectory()+File.separator+
Common.getUniqueTestIdentifier(QASHFileName)+"_"+processIDName.toString(),
grepString.toString());
setProperty(result.toString(),resultCode);
}
catch (Exception e) {
printError(STDOUTCONTAINS,"Problem processing STDOUTCONTAINS command ("+e.toString()+") :",currToken);
}
}
/**
* Returns 0 if the commandId contains the specified String in the stdout trace,
* else returns 1. This command should only be called if the trace
* was retrieved by a call to CMDGETTRACE(...)
* SYNTAX: STDERRCONTAINS(processID, result, matchstring)
* Warning : Do not call this method until after the output has been retrieved.
*/
private void processSTDERRCONTAINS() {
try {
expectLeftParenthesis();
QASHToken processIDName = resolveName(getTokensUntil(COMMA));
QASHToken result = resolveName(getTokensUntil(COMMA));
QASHToken grepString = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
QASHToken processID = getToken(processIDName);
setStatusText(QASHConstants.getTokenValue(STDERRCONTAINS),grepString.toString());
if (processIDName==null)
throw new Exception("Invalid process ID");
AgentInstance agentInstance = getAgentRunningProcess(processID.toString());
if (agentInstance==null)
throw new Exception("Unknown processID");
String resultCode;
resultCode = agentInstance.STDERRCONTAINS(processID.toString(),
qashProperties.getProjectResultsDirectory()+File.separator+
Common.getUniqueTestIdentifier(QASHFileName)+"_"+processIDName.toString(),
grepString.toString());
setProperty(result.toString(),resultCode);
}
catch (Exception e) {
printError(STDERRCONTAINS,"Problem processing STDERRCONTAINS command ("+e.toString()+") :",currToken);
}
}
/**
* Returns the actual paths to the specified process trace files
* relative to the agent. Only valid before the call to
* CMDCLEAN(...), since that call will delete these files.
* SYNTAX: GETTRACEPATHS(processID, env, stdout, stderr)
* This may be called even if the output is not retrieved
* from the agent.
*/
private void processGETTRACEPATHS() {
try {
expectLeftParenthesis();
QASHToken processIDName = resolveName(getTokensUntil(COMMA));
QASHToken envFileName = resolveName(getTokensUntil(COMMA));
QASHToken stdoutFileName= resolveName(getTokensUntil(COMMA));
QASHToken stderrFileName= resolveName(getTokensUntil(RIGHT_PARENTHESIS));
QASHToken processID = getToken(processIDName);
setStatusText(QASHConstants.getTokenValue(GETTRACEPATHS),processIDName.toString());
if (processIDName==null)
throw new Exception("Invalid process ID");
AgentInstance agentInstance = getAgentRunningProcess(processID.toString());
if (agentInstance==null)
throw new Exception("Unknown process ID");
String results[] = agentInstance.GETTRACEPATHS(processID.toString());
setProperty(envFileName.toString(),results[0]);
setProperty(stdoutFileName.toString(),results[1]);
setProperty(stderrFileName.toString(),results[2]);
}
catch (Exception e) {
printError(GETTRACEPATHS,"Problem processing GETTRACEPATHS command ("+e.toString()+") :",currToken);
}
}
/**
* Cleans the stdout and stderr files created by the process.
* SYNTAX: CMDCLEAN(processID)
* Warning : Do not call this method until after the output has been retrieved.
*/
private void processCMDCLEAN() {
try {
List<QASHToken> expression = readExpression(false, true);
QASHToken processIDName = resolveName(expression);
QASHToken processID = getToken(processIDName);
AgentInstance agentInstance = getAgentRunningProcess(processID.toString());
setStatusText(QASHConstants.getTokenValue(CMDCLEAN),processIDName.toString());
if (agentInstance==null)
throw new Exception("Unknown processID :"+processID.toString());
agentInstance.CMDCLEAN(processID.toString());
removeProperty(processIDName.toString());
}
catch (Exception e) {
printError(CMDCLEAN,"Error processing CMDCLEAN command ("+e.toString()+") :",currToken);
}
}
/**
* This method causes the shell to sleep for the specified number of seconds. All
* background processes carry on unchanged.
* SYNTAX: SLEEP(value), where value is the number of seconds to sleep.
*/
private void processSLEEP() {
try {
List<QASHToken> expression = readExpression(false, true);
QASHToken secondsStr = resolveExpression(expression);
int seconds = secondsStr.intValue();
if (!inEvaluationMode()) {
while((seconds>0)&&(!isInterrupted())) {
Utils.safeSleep(1);
seconds--;
setStatusText(QASHConstants.getTokenValue(SLEEP),Integer.toString(seconds));
}
}
}
catch (Exception e) {
printError(SLEEP,"Invalid time value for SLEEP statement ("+e.toString()+") :",currToken);
}
}
/**
* This method is for the test to communicate the outcome of the test to the test harness.
* SYNTAX: REPORTSTATUS(value), where value is expected to be an integer value.
* 0 indicates the test passed, and other value signifies it failed. If parse errors were encountered
* the test status will always be reported as UNRESOLVED.
*/
private void processREPORTSTATUS() {
try {
List<QASHToken> expression = readExpression(false, true);
QASHToken status = resolveExpression(expression);
setStatusText(QASHConstants.getTokenValue(REPORTSTATUS),status.toString());
// unresolved always overrides any test result
if (getStatus() != ProtocolConstants.UNRESOLVED) {
if (inEvaluationMode()) {
setStatus(ProtocolConstants.PASSED);
}
else {
if ((new Integer(status.intValue()).intValue())==0) {
setStatus(ProtocolConstants.PASSED);
}
else {
if (getTestBugInfo().equals("")) {
setStatus(ProtocolConstants.FAILED);
}
else {
setStatus(ProtocolConstants.PENDING);
}
}
}
}
setStatusReported(true);
}
catch (Exception e) {
printError(REPORTSTATUS,"Invalid status reported ("+e.toString()+") :",currToken);
}
finally {
if (qashProperties.isAutoClean())
autoClean();
}
}
/**
* This method is used to generate a positive random integer in the QASH scripts for
* use in defining tmp directory offset etc.
* SYNTAX: RANDOM(id), where id will contain the random integer value after this call is made.
*/
private void processRANDOM() {
setStatusText(currToken.toString());
try {
List<QASHToken> expression = readExpression(false, false);
QASHToken randomVar = resolveName(expression);
setProperty(randomVar,Integer.toString(Math.abs(new Random().nextInt())));
}
catch (Exception e) {
printError(RANDOM,"Invalid syntax in RANDOM command ("+e.toString()+") :",currToken);
}
}
/**
* Used for debugging - prints out the current contents of the qash properties.
*/
@SuppressWarnings("unchecked")
private void processPRINTENV() {
setStatusText(currToken.toString());
try {
printStream.println("Defined variables:");
String key;
for (Enumeration<String> e = (Enumeration<String>) properties.propertyNames() ; e.hasMoreElements() ;) {
key = (String)e.nextElement();
printStream.println(key+"="+properties.getProperty(key));
}
//printStream.println(properties);
printStream.println("Defined static variables:");
printStream.println(staticVariables);
}
catch (Exception e) {
printError(PRINTENV,"Invalid PRINTENV reported ("+e.toString()+") :",currToken);
}
}
/**
* This method will clear all agents referenced by this parse session in case
* this user forgets to clear something, or if an error occurs in the parse
* process.
*/
private void autoClean() {
printDebug("Processing AUTOCLEAN of "+qashProperties.getActiveAgentCount()+" agent(s)");
// now call kill for all active agents
if (!inEvaluationMode()) {
AgentInstance agent=null;
for (Enumeration<AgentInstance> agentList = qashProperties.getActiveAgents() ; agentList.hasMoreElements() ;) {
try {
agent = (AgentInstance)agentList.nextElement();
agent.KILLSTARTEDPROCESSES();
}
catch (Exception e) {
printError(3,"Error during AUTOCLEAN of one or more agent processes - may need restart of agents!"+" :"+e.toString());
}
}
}
// clear our Hashtable now
qashProperties.clearActiveAgents();
}
/**
* After calling this keyword, when calling REPORTSTATUS, any related zips will be cleaned,
* commands run will be stopped, and their traces cleaned.
*/
private void processAUTOCLEAN_ON() {
try {
qashProperties.setAutoClean(true);
printDebug("AUTOCLEAN enabled");
}
catch (Exception e) {
printError(AUTOCLEAN_ON,"Invalid AUTOCLEAN_ON reported ("+e.toString()+") :",currToken);
}
}
/**
* After calling this keyword, when calling REPORTSTATUS, any related zips will not be cleaned,
* commands run will not be stopped, and their traces will not cleaned.
* By default, this behaviour is enabled.
*/
private void processAUTOCLEAN_OFF() {
try {
qashProperties.setAutoClean(false);
printDebug("AUTOCLEAN disabled");
}
catch (Exception e) {
printError(AUTOCLEAN_OFF,"Invalid AUTOCLEAN_OFF reported ("+e.toString()+") :",currToken);
}
}
/**
* Gets an arbitrary file from the agent.
* SYNTAX: GETFILE(agentid, src, dest), where src is the file path on the agent, and dest is the path on
* the harness to place the file in.
*/
private void processGETFILE() {
try {
expectLeftParenthesis();
QASHToken agentID = resolveExpression(getTokensUntil(COMMA));
QASHToken src = resolveExpression(getTokensUntil(COMMA));
QASHToken dest = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
// check that this agentID is defined
if (agentID==null) {
throw new Exception("agentID Identifier not defined");
}
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID");
else
agentInstance.GETFILE(src.toString(),dest.toString());
}
catch (Exception e) {
printError(GETFILE,"Problem processing GETFILE command ("+e.toString()+") :",currToken);
}
}
/**
* Sends an arbitrary file to the agent.
* SYNTAX: SENDFILE(agentid, src, dest), where src is the file path on the harness, and dest is the path on
* the agent to place the file in.
*/
private void processSENDFILE() {
try {
expectLeftParenthesis();
QASHToken agentID = resolveExpression(getTokensUntil(COMMA));
QASHToken src = resolveExpression(getTokensUntil(COMMA));
QASHToken dest = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
// check that this agentID is defined
if (agentID==null) {
throw new Exception("agentID Identifier not defined");
}
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID");
else
agentInstance.SENDFILE(src.toString(),dest.toString());
}
catch (Exception e) {
printError(SENDFILE,"Problem processing SENDFILE command ("+e.toString()+") :",currToken);
}
}
/**
* Checks whether an arbitrary file exists on the agent or not.
* SYNTAX: CHECKFILE(agentid, result, filename), where result is zero if the file exists, non-zero if it doesn't exist,
* and filename is the name of the file to check relative to the agent.
*/
private void processCHECKFILE() {
try {
expectLeftParenthesis();
QASHToken agentID = resolveExpression(getTokensUntil(COMMA));
QASHToken result = resolveName(getTokensUntil(COMMA));
QASHToken filename = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
setStatusText(QASHConstants.getTokenValue(CHECKFILE),filename.toString());
// check that this agentID is defined
if (agentID==null) {
throw new Exception("agentID Identifier not defined");
}
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID");
else
setProperty(result,agentInstance.CHECKFILE(filename.toString()));
}
catch (Exception e) {
printError(CHECKFILE,"Problem processing CHECKFILE command ("+e.toString()+") :",currToken);
}
}
/**
* Checks whether an arbitrary file exists on the harness side or not.
* SYNTAX: CHECKFILE_LOCAL(result, filename), where result is zero if the file exists, non-zero if it doesn't exist,
* and filename is the name of the file to check relative to the harness.
* If the parser is running in evaluation mode, the result will always be zero.
*/
private void processCHECKFILE_LOCAL() {
try {
expectLeftParenthesis();
QASHToken result = resolveName(getTokensUntil(COMMA));
QASHToken filename = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
setStatusText(QASHConstants.getTokenValue(CHECKFILE_LOCAL),filename.toString());
if (!inEvaluationMode()) {
setProperty(result.toString(),((new File(filename.toString())).exists() ? "0" : "1" ));
}
else {
setProperty(result.toString(),"0");
}
}
catch (Exception e) {
printError(CHECKFILE,"Problem processing CHECKFILE_LOCAL command ("+e.toString()+") :",currToken);
}
}
/**
* Checks whether an arbitrary agent can be reached or not.
* SYNTAX: CHECKAGENT(result,agentname,agentport), where result is zero if the agent exists, non-zero if it doesn't exist.
* In evaluation mode it will always return 0.
*/
@SuppressWarnings("unchecked")
private void processCHECKAGENT() {
try {
expectLeftParenthesis();
QASHToken result = resolveName(getTokensUntil(COMMA));
QASHToken agentName = resolveExpression(getTokensUntil(COMMA));
QASHToken agentPort = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
setStatusText(QASHConstants.getTokenValue(CHECKAGENT),agentName.toString());
Socket socket = null;
DataInputStream inStream = null;
DataOutputStream outStream = null;
String resultCode ="0";
if (!inEvaluationMode()) {
try {
socket = new Socket(agentName.toString(),(new Integer(agentPort.toString())).intValue());
socket.setSoTimeout(3000);
inStream = new DataInputStream(socket.getInputStream());
outStream = new DataOutputStream(socket.getOutputStream());
outStream.writeInt(ProtocolConstants.CHECKAGENT);
if (inStream.readInt()!=ProtocolConstants.RESPONSE_PROCESSING)
throw new Exception("Error response from agent");
// read the number of properties being sent
int propertyCount = inStream.readInt();
String key, value;
for (int i = 0; i < propertyCount; i++) {
key = agentName+"."+inStream.readUTF();
value = inStream.readUTF();
setProperty(key,value);
}
if (inStream.readInt()!=ProtocolConstants.RESPONSE_FINISHED_OK)
throw new Exception("Error response from agent");
}
catch (ConnectException e) {
resultCode = "1";
}
finally {
if (inStream != null) inStream.close();
if (outStream != null) outStream.close();
if (socket != null) socket.close();
}
}
else {
// in eval mode, we set agent properties to use our properties
Properties propertiesT = System.getProperties();
String key, value;
for (Enumeration<String> e = (Enumeration<String>) propertiesT.propertyNames() ; e.hasMoreElements() ;) {
key = e.nextElement().toString();
value = propertiesT.getProperty(key);
key = agentName+"."+key;
setProperty(key,value);
}
}
setProperty(result,resultCode);
}
catch (Exception e) {
printError(CHECKAGENT,"Problem processing CHECKAGENT command ("+e.toString()+") :",currToken);
}
}
/**
* Checks whether an arbitrary agent can be reached or not.
* SYNTAX: KILLAGENT(result,agentname,agentport), where result is zero if the agent exists, non-zero if it doesn't exist.
* In evaluation mode it will always return 0.
*/
private void processKILLAGENT() {
try {
expectLeftParenthesis();
QASHToken result = resolveName(getTokensUntil(COMMA));
QASHToken agentName = resolveExpression(getTokensUntil(COMMA));
QASHToken agentPort = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
setStatusText(QASHConstants.getTokenValue(KILLAGENT),agentName.toString());
Socket socket = null;
DataInputStream inStream = null;
DataOutputStream outStream = null;
String resultCode ="0";
if (!inEvaluationMode()) {
try {
socket = new Socket(agentName.toString(),(new Integer(agentPort.toString())).intValue());
socket.setSoTimeout(3000);
inStream = new DataInputStream(socket.getInputStream());
outStream = new DataOutputStream(socket.getOutputStream());
outStream.writeInt(ProtocolConstants.KILLAGENT);
if (inStream.readInt()!=ProtocolConstants.RESPONSE_PROCESSING)
throw new Exception("Error response from agent");
if (inStream.readInt()!=ProtocolConstants.RESPONSE_FINISHED_OK)
throw new Exception("Error response from agent");
}
catch (ConnectException e) {
resultCode = "1";
}
finally {
if (inStream != null) inStream.close();
if (outStream != null) outStream.close();
if (socket != null) socket.close();
}
}
setProperty(result,resultCode);
}
catch (Exception e) {
printError(CHECKAGENT,"Problem processing KILLAGENT command ("+e.toString()+") :",currToken);
}
}
/**
* Defines a function for later use by the qash scripts.
* SYNTAX: FUNCTION(func_name), where func_name is the name to be used
* later on when calling the function via CALLFUNCTION(func_name) command.
*/
private void processFUNCTION() {
try {
expectLeftParenthesis();
QASHToken functionName = resolveName(getTokensUntil(COMMA));
// now read parameters, if any
List<QASHToken> parameters = new ArrayList<QASHToken>();
QASHToken token;
do {
token = getNextToken();
if ((token.ttype != COMMA)&&
(token.ttype != RIGHT_PARENTHESIS)) {
parameters.add(token);
}
} while ((token.ttype != RIGHT_PARENTHESIS)&&
(token.ttype != QASHToken.TT_EOF));
parameters.add(0,new QASHToken(Integer.toString(parameters.size()),QASHToken.ARG_COUNT,0));
// process the function body
List<QASHToken> functionBody = new ArrayList<QASHToken>();
int nestedCount = 1;
if (qashProperties.getFunction(functionName.toString())!=null) {
throw new Exception("Function "+functionName.toString()+" is already defined");
}
do {
token = getNextToken();
switch (getTokenID(token.toString())) {
case FUNCTION :
nestedCount++;
break;
case ENDFUNCTION :
nestedCount--;
break;
default : functionBody.add(token);
}
} while ((getTokenID(token.toString())!=ENDFUNCTION)&&
(token.ttype != QASHToken.TT_EOF)&&
(nestedCount>0));
if (nestedCount>0)
throw new Exception("Missing ENDFUNCTION statement");
// insert our parameters
for (int i = parameters.size()-1; i >= 0; i--)
functionBody.add(0,parameters.get(i));
// now add this mini stack to out static hashtable
qashProperties.addFunction(functionName.toString(),functionBody);
}
catch (Exception e) {
printError(FUNCTION,"Problem processing FUNCTION command ("+e.toString()+") :",currToken);
}
}
/**
* Defines a function for later use by the qash scripts.
* SYNTAX: CALLFUNCTION(func_name), where func_name is the name used
* previously when being defined by the FUNCTION(func_name) command.
*
*/
private void processCALLFUNCTION() {
try {
expectLeftParenthesis();
QASHToken functionName = resolveName(getTokensUntil(COMMA));
List<QASHToken> functionBodyCopy = (ArrayList<QASHToken>) qashProperties.getFunction(functionName.toString());
if (functionBodyCopy==null) {
throw new Exception("Function "+functionName.toString()+" is not defined");
}
else {
functionBodyCopy = Utils.clone(functionBodyCopy);
}
// pop off the args count
int argCount = Integer.parseInt(functionBodyCopy.remove(0).toString());
// now read parameters passed to call this function with
List<QASHToken> expr = new ArrayList<QASHToken>();
List<QASHToken> args = new ArrayList<QASHToken>();
QASHToken token;
do {
token = getNextToken();
switch (token.ttype) {
case RIGHT_PARENTHESIS :
case COMMA :
args.add(functionBodyCopy.remove(0));
args.add(new QASHToken(SET_OPERATOR,SET_OPERATOR,0));
args.add(resolveExpression(expr));
args.add(new QASHToken(SEMICOLON,SEMICOLON,0));
expr.clear();
argCount--;
break;
default :
expr.add(token);
}
} while ((token.ttype!=RIGHT_PARENTHESIS)&&
(token.ttype != QASHToken.TT_EOF));
if (argCount!=0)
throw new Exception("Incorrect argument count for function "+functionName);
pushOntoStack(functionBodyCopy);
pushOntoStack(args);
}
catch (Exception e) {
printError(CALLFUNCTION,"Problem processing CALLFUNCTION command ("+e.getMessage()+") :",currToken);
}
}
/**
* Deletes an arbitrary file on the harness machine.
* SYNTAX: DELFILE_LOCAL(filename), where src is the file path relative to the harness.
* Use with caution - if filename is a directory, it and all it's subdirectories will be deleted!
* If the parser is running in evaluation mode, this command will have no action.
*/
private void processDELFILE_LOCAL() {
try {
List<QASHToken> expression = readExpression(false, true);
QASHToken filename = resolveExpression(expression);
setStatusText(QASHConstants.getTokenValue(DELFILE_LOCAL),filename.toString());
if (!inEvaluationMode()) {
if (!(new File(filename.toString())).exists())
throw new Exception("Cannot delete - file does not exist ("+filename.toString()+")");
else
Utils.delete(filename.toString());
}
}
catch (Exception e) {
printError(DELFILE_LOCAL,"Problem processing DELFILE_LOCAL command ("+e.toString()+") :",currToken);
}
}
/**
* Deletes an arbitrary file on the harness machine.
* SYNTAX: DELFILE(agentid, filename), where agentid refers to the agent machine where the file resides,
* and src is the file path for deletion relative to the agent.
* Use with caution - if filename is a directory, it and all it's subdirectories will be deleted!
*/
private void processDELFILE() {
try {
expectLeftParenthesis();
QASHToken agentID = resolveExpression(getTokensUntil(COMMA));
QASHToken filename = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
setStatusText(QASHConstants.getTokenValue(DELFILE),filename.toString());
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID");
else
agentInstance.DELFILE(filename.toString());
}
catch (Exception e) {
printError(DELFILE,"Problem processing DELFILE command ("+e.toString()+") :",currToken);
}
}
/**
* Deletes an arbitrary file on the harness machine.
* SYNTAX: MKDIR(agentid, dirname), where agentid refers to the agent machine where the file resides,
* and dir is the file path for the directory to be created..
* If the parent directories specified in the dirname path do not exist, they will be created.
*/
private void processMKDIR() {
try {
expectLeftParenthesis();
QASHToken agentID = resolveExpression(getTokensUntil(COMMA));
QASHToken filename = resolveExpression(resolveExpression(getTokensUntil(RIGHT_PARENTHESIS)));
setStatusText(QASHConstants.getTokenValue(MKDIR),filename.toString());
AgentInstance agentInstance = (AgentInstance)qashProperties.getActiveAgent(new Integer(agentID.toString()));
if (agentInstance==null)
throw new Exception("Unknown agentID");
else
agentInstance.MKDIR(filename.toString());
}
catch (Exception e) {
printError(MKDIR,"Problem processing MKDIR command ("+e.toString()+") :",currToken);
}
}
/**
* Creates a directory on the harness machine.
* SYNTAX: MKDIR_LOCAL(filename), where src is the dir path relative to the harness.
* If the parser is running in evaluation mode, this command will have no action.
*/
private void processMKDIR_LOCAL() {
try {
expectLeftParenthesis();
QASHToken filename = null;
filename = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
setStatusText(QASHConstants.getTokenValue(MKDIR_LOCAL),filename.toString());
if (!inEvaluationMode()) {
Utils.touchDir(fileName.toString());
}
}
catch (Exception e) {
printError(MKDIR_LOCAL,"Problem processing MKDIR_LOCAL command ("+e.toString()+") :",currToken);
}
}
/**
* Set a property which will be accesible to other scripts for the lieftime of the JVM, or until it is deleted by a call to
* DELSTATIC .
* SYNTAX : SETSTATIC(KEY, VALUE)
*/
private void processSETSTATIC() {
try {
expectLeftParenthesis();
QASHToken key = resolveName(getTokensUntil(COMMA));
QASHToken value = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
staticVariables.setProperty(key.toString(),value.toString());
}
catch (Exception e) {
printError(SETPROP,"Problem processing SETSTATIC command ("+e.toString()+") :",currToken);
}
}
/**
* Removes a previously set static variable.
* SYNTAX : DELSTATIC(KEY)
*/
private void processDELSTATIC() {
try {
expectLeftParenthesis();
QASHToken key = resolveName(getTokensUntil(RIGHT_PARENTHESIS));
staticVariables.remove(key.toString());
}
catch (Exception e) {
printError(SETPROP,"Problem processing DELSTATIC command ("+e.toString()+") :",currToken);
}
}
/**
* Retrieves a previously set static variable.
* If the variable specified by KEY does not exist, RESULT willbe undefined and attempts to
* use it will generate an error.
* SYNTAX : GETSTATIC(RESULT, KEY)
*/
private void processGETSTATIC() {
try {
expectLeftParenthesis();
QASHToken result = resolveName(getTokensUntil(COMMA));
QASHToken key = resolveExpression(getTokensUntil(RIGHT_PARENTHESIS));
String value = (String)staticVariables.getProperty(key.toString(),"").toString();
if (value!="") {
setProperty(result.toString(), value);
}
else {
removeProperty(result.toString());
printWarning(45,"Static variable not defined :"+key);
}
}
catch (Exception e) {
printError(SETPROP,"Problem processing GETSTATIC command ("+e.toString()+") :",currToken);
}
}
/**
* Looks through currently running agents for an identifier matching processID.
* Returns the matching AgentInstance, or null if it wasn't found.
*/
private AgentInstance getAgentRunningProcess(String processID) {
try {
AgentInstance agentInstance;
for (Enumeration<AgentInstance> e = qashProperties.getActiveAgents() ; e.hasMoreElements() ;) {
agentInstance = (AgentInstance)e.nextElement();
if (agentInstance.isHandlingProcess(processID)) {
return agentInstance;
}
}
}
catch(Exception e) {
printError(23,"No agent was running this process!");
}
return null;
}
/**
* Looks through currently running agents for an identifier matching zipID.
* Returns the matching AgentInstance, or null if it wasn't found.
*/
private AgentInstance getAgentForZip(String zipID) {
AgentInstance agentInstance;
for (Enumeration<AgentInstance> e = qashProperties.getActiveAgents() ; e.hasMoreElements() ;) {
agentInstance = (AgentInstance)e.nextElement();
if (agentInstance.isHandlingZip(zipID)) {
return agentInstance;
}
}
return null;
}
private static List<QASHToken> removeRange(List<QASHToken> array, int start, int end) {
int count = end - start;
for (int i = 0; i < count ; i++) {
array.remove(start);
}
return array;
}
private List<QASHToken> copyRange(List<QASHToken> array, int start, int end) {
List<QASHToken> result = new ArrayList<QASHToken>(end-start);
for (int i = 0; i < (end-start); i++)
result.add(array.get(i+start));
return result;
}
/**
* This method takes a list of tokens, and processes all the concat & parenthesis stuff but
* does not actually dereference any variables in it unless they
* exists along with other concat operators and constants.
* eg. TOTO will stay TOTO, but TOTO+"xxx" will return "valxxx", assuming
* TOTO was set to "val".
*/
private QASHToken resolveName(List<QASHToken> expression) throws Exception {
if (indexOf(expression,CONCAT_OPERATOR)>0)
return resolveNameInternal(expression,true);
else
return resolveNameInternal(expression,false);
}
private QASHToken resolveNameInternal(List<QASHToken> expression, boolean referenceLast) throws Exception {
QASHToken token = (QASHToken)((QASHToken)expression.get(0)).clone();
// maybe we are finished already
if (expression.size()==1) {
if ((referenceLast)&
(token.ttype==QASHToken.TT_WORD))
return getToken(token);
else
return token;
}
switch (token.ttype) {
case LEFT_PARENTHESIS :
List<QASHToken> inside = Utils.clone(expression);
int rindex = getClosingParenIndex(inside,0);
inside = removeRange(inside,rindex,inside.size());
inside.remove(0);
expression=removeRange(expression,0,rindex+1);
if (inside.size()>0)
expression.add(0,resolveNameInternal(inside,referenceLast));
return resolveNameInternal(expression,referenceLast);
case CONCAT_OPERATOR :
expression.remove(0);
return resolveNameInternal(expression,referenceLast);
case QASHToken.TT_WORD :
expression.remove(0);
QASHToken newtoken = getToken(token);
if (newtoken==null) {
throw new Exception("Undefined symbol "+token);
}
else {
return newtoken.append(resolveNameInternal(expression,referenceLast));
}
default :
expression.remove(0);
if (expression.size()>0)
token.append(resolveNameInternal(expression,referenceLast));
return token;
}
}
/**
* This method replaces all the variable token by the actual values, or returns an error if
* the value is not defined.
*/
private QASHToken resolveExpression(QASHToken token) throws Exception {
List<QASHToken> arrayList = new ArrayList<QASHToken>(1);
arrayList.add(token);
return resolveExpression(arrayList);
}
/**
* This method replaces all variables by actual values, or returns an error if
* any of the values are not defined. It process concat operators as well.
*/
private QASHToken resolveExpression(List<QASHToken> expression) throws Exception {
return resolveExpressionInternal(expression,true);
}
private QASHToken resolveExpressionInternal(List<QASHToken> expression, boolean strict) throws Exception {
QASHToken token;
// maybe we are finished already
if (expression.size()==0) {
return null;
}
else {
// the clone is important here, else we change
// the referenced value all the way through
token = (QASHToken)((QASHToken)expression.get(0)).clone();
}
switch (token.ttype) {
case LEFT_PARENTHESIS :
List<QASHToken> inside = Utils.clone(expression);
int rindex = getClosingParenIndex(inside,0);
inside = removeRange(inside,rindex,inside.size());
inside.remove(0);
expression=removeRange(expression,0,rindex+1);
if (inside.size()>0)
expression.add(0,resolveExpressionInternal(inside,strict));
// now since we enclosed it in brackets, try and evaluate it
// further as a VARIABLE name instead of a value
QASHToken tmp;
if ((tmp = getToken((QASHToken)expression.get(0)))!=null) {
expression.set(0,tmp);
}
return resolveExpressionInternal(expression,strict);
case CONCAT_OPERATOR :
expression.remove(0);
return resolveExpressionInternal(expression,strict);
case QASHToken.TT_STRING :
expression.remove(0);
token.append(resolveExpressionInternal(expression,strict));
return token;
case QASHToken.TT_NUMBER :
expression.remove(0);
QASHToken theRest = resolveExpressionInternal(expression,strict);
if (theRest!=null) {
try {
int v1 = Integer.parseInt(token.toString());
int v2 = Integer.parseInt(theRest.toString());
return new QASHToken(Integer.toString(v1+v2),QASHToken.TT_NUMBER,theRest.line);
}
catch (NumberFormatException e) {
token.append(theRest);
return token;
}
}
else return token;
case QASHToken.TT_WORD :
expression.remove(0);
QASHToken value = getToken(token);
if (value==null) {
if (strict) {
throw new Exception("Reference to undefined variable "+token.toString());
}
}
else {
token = value.append(resolveExpressionInternal(expression,strict));
}
return token;
default :
expression.remove(0);
token.append(resolveExpressionInternal(expression,strict));
return token;
}
}
/**
* This method returns the index of the c in the expression list,
* or -1 if it is not found.
*/
private int indexOf(List<QASHToken> expression, char c) {
for (int i = 0 ; i < expression.size(); i++)
if (((QASHToken)expression.get(i)).ttype==c)
return i;
return -1;
}
private QASHToken getToken(String key) {
return getToken(key,null);
}
private QASHToken getToken(QASHToken key) {
return getToken(key.toString());
}
private QASHToken getToken(String key, String defaultValue) {
String value = getProperty(key,defaultValue);
if (value!=null) {
QASHToken token = new QASHToken(value,currToken.line);
return token;
}
// backward compat start - remove for 2.6.5
return backwardsCompat(key,defaultValue);
// return null;
// backward compat end - remove for 2.6.5
}
// backward compat start - remove for 2.6.5
private QASHToken backwardsCompat(String key, String defaultValue) {
if (key.indexOf("TESTPATH")>=0) {
printWarning(8765,"Please use qat.project.path instead of TESTPATH");
return new QASHToken(getProperty("qat.project.path",defaultValue),currToken.line);
}
if (key.indexOf("AGENT_COUNT")>=0) {
printWarning(8765,"Please use qat.agent.count instead of AGENT_COUNT");
return new QASHToken(getProperty("qat.agent.count",defaultValue),currToken.line);
}
if (key.indexOf("TEST_NAME")>=0) {
printWarning(8765,"Please use qat.test.name instead of TEST_NAME");
return new QASHToken(getProperty("TEST_NAME",defaultValue),currToken.line);
}
if (key.indexOf("TEST_AUTHOR")>=0) {
printWarning(8765,"Please use qat.test.author instead of TEST_AUTHOR");
return new QASHToken(getProperty("TEST_AUTHOR",defaultValue),currToken.line);
}
if (key.indexOf("TEST_DESCRIPTION")>=0) {
printWarning(8765,"Please use qat.test.description instead of TEST_DESCRIPTION");
return new QASHToken(getProperty("TEST_DESCRIPTION",defaultValue),currToken.line);
}
if (key.indexOf("BUG_INFO")>=0) {
printWarning(8765,"Please use qat.test.buginfo instead of BUG_INFO");
return new QASHToken(getProperty("BUG_INFO",defaultValue),currToken.line);
}
if (key.indexOf("KEYWORDS")>=0) {
printWarning(8765,"Please use qat.test.keywords instead of KEYWORDS");
return new QASHToken(getProperty("KEYWORDS",defaultValue),currToken.line);
}
if (key.startsWith("AGENT")) {
String agent = key.substring(0,6).toLowerCase();
if (key.indexOf("_NAME")>0) {
printWarning(8765,"Please use agent1.name instead of AGENT1_NAME");
return new QASHToken(getProperty(agent+".name",defaultValue),currToken.line);
}
if (key.indexOf("_PORT")>0) {
printWarning(8765,"Please use agent1.port instead of AGENT1_PORT");
return new QASHToken(getProperty(agent+".port",defaultValue),currToken.line);
}
if (key.indexOf("_ARCH")>0) {
printWarning(8765,"Please use agent1.os.architecture instead of AGENT1_ARCH");
return new QASHToken(getProperty(agent+".os.architecture",defaultValue),currToken.line);
}
if (key.indexOf("_OSNAME")>0) {
printWarning(8765,"Please use agent1.os.name instead of AGENT1_OSNAME");
return new QASHToken(getProperty(agent+".os.name",defaultValue),currToken.line);
}
}
return null;
}
// backward compat end - remove for 2.6.5
public String getProperty(String key) {
return getProperty(key,"");
}
public String getProperty(String key, String defaultValue) {
return properties.getProperty(key,defaultValue);
}
public final Properties getProperties() {
return properties;
}
public void setProperty(QASHToken key, QASHToken value) {
setProperty(key.toString(),value.toString());
}
public void setProperty(QASHToken key, String value) {
setProperty(key.toString(),value);
}
public void setProperty(String key, String value) {
properties.setProperty(key,value);
}
public void removeProperty(QASHToken key) {
removeProperty(key.toString());
}
public void removeProperty(String key) {
properties.remove(key);
}
public void printDebug(String msg) {
printStream.printBold("[ ");
printStream.print(HtmlPrintStream.PURPLE,msg);
printStream.printBoldln(" ]");
}
private void printWarning(int code, String msg) {
log.warning(msg);
printStream.printBold("[ ");
printStream.print(HtmlPrintStream.BLUE,"Warning ");
printStream.print("("+code+") :");
printStream.print(msg);
printStream.print(" in file ");
printStream.print(HtmlPrintStream.BLUE,fileName);
printStream.printBoldln(" ]");
}
private void printError(int code, String msg) {
// make sure we only print the first error - others are
// usually spurious
if (getStatus()!=ProtocolConstants.UNRESOLVED) {
printStream.printBold("[ ");
printStream.print(HtmlPrintStream.RED,"Error ");
printStream.print("(");
printStream.print(code);
printStream.print(") :");
printStream.print(msg);
printStream.print(" in file ");
printStream.print(HtmlPrintStream.RED,fileName);
printStream.printBoldln(" ]");
setStatus(ProtocolConstants.UNRESOLVED);
}
}
private void printError(int code, String msg, QASHToken token) {
printError(code,msg,token.line);
}
private void printError(int code, String msg, int line) {
printError(code,msg+" on line "+line);
}
private void expectLeftParenthesis() throws Exception {
getNextToken();
if (currToken.ttype!=LEFT_PARENTHESIS)
throw new Exception("Expected ( instead of "+currToken.toString());
}
/*------- these are the boolean expression handling routines ----------*/
/**
* This method replaces all CONCAT_OPERATOR ops found in the expression
* with the concatenated result.
*/
private List<QASHToken> preProcessBooleanExpression(List<QASHToken> expression) throws Exception {
for (int i = 1; i < expression.size()-1; i++) {
QASHToken token = (QASHToken)expression.get(i);
if (token.ttype==CONCAT_OPERATOR) {
// append the previous token and the next token. This
// is to handle simple appends in a boolean statement
// such as (I+"2">4) and ((I+"2")>4)
List<QASHToken> miniExpression = new ArrayList<QASHToken>(5);
miniExpression.add(new QASHToken(LEFT_PARENTHESIS,LEFT_PARENTHESIS,token.line));
miniExpression.add((QASHToken)expression.get(i-1));
miniExpression.add(token);
miniExpression.add(((QASHToken)expression.get(i+1)));
miniExpression.add(new QASHToken(RIGHT_PARENTHESIS,RIGHT_PARENTHESIS,token.line));
expression.set(i-1,resolveExpression(miniExpression));
expression.remove(i);
expression.remove(i);
}
}
return expression;
}
private boolean evaluateBooleanExpression(List<QASHToken> expression) throws Exception {
return evaluateBooleanExpression(createExpressionTree(preProcessBooleanExpression(expression)));
}
private boolean evaluateBooleanExpression(QASHTree root) throws Exception {
if ((root.left.isLeaf())&&(root.right.isLeaf())) {
return evaluateBooleanNode(root.left.value,root.value,root.right.value);
}
else {
switch (root.value.ttype) {
case LOGICAL_AND : return (evaluateBooleanExpression(root.left) & evaluateBooleanExpression(root.right));
case LOGICAL_OR : return (evaluateBooleanExpression(root.left) | evaluateBooleanExpression(root.right));
case EQUALITY_OPERATOR : return (evaluateBooleanExpression(root.left) == evaluateBooleanExpression(root.right));
case NOT_EQUAL_OPERATOR : return (evaluateBooleanExpression(root.left) != evaluateBooleanExpression(root.right));
default : throw new Exception("Unknown operator encountered :"+root.value);
}
}
}
private boolean evaluateBooleanNode(QASHToken left, QASHToken operator, QASHToken right) throws Exception {
QASHToken leftSideValue;
if (left.ttype==QASHToken.TT_WORD)
leftSideValue = getToken(left);
else
leftSideValue = left; // already evaluated
QASHToken rightSideValue;
if (right.ttype==QASHToken.TT_WORD)
rightSideValue = getToken(right);
else
rightSideValue = right; // already evaluated
// now first try a numerical comparison
try {
switch (operator.ttype) {
case GREATER_THAN :
return (leftSideValue.intValue() > rightSideValue.intValue());
case LESS_THAN :
return (leftSideValue.intValue() < rightSideValue.intValue());
case EQUALITY_OPERATOR :
return (leftSideValue.equals(rightSideValue));
case NOT_EQUAL_OPERATOR :
return (!(leftSideValue.equals(rightSideValue)));
case LESS_THAN_EQ :
return (leftSideValue.intValue() <= rightSideValue.intValue());
case GREATER_THAN_EQ :
return (leftSideValue.intValue() >= rightSideValue.intValue());
default :
throw new Exception("Unknown operator type :"+operator);
}
}
catch (NumberFormatException e) {
// make the comparison as "String <operator> String"
switch (operator.ttype) {
case GREATER_THAN :
return (leftSideValue.compareTo(rightSideValue)>0);
case LESS_THAN :
return (leftSideValue.compareTo(rightSideValue)<0);
case EQUALITY_OPERATOR :
return (leftSideValue.equals(rightSideValue));
case NOT_EQUAL_OPERATOR :
return (!leftSideValue.equals(rightSideValue));
case LESS_THAN_EQ :
return (leftSideValue.compareTo(rightSideValue)<=0);
case GREATER_THAN_EQ :
return (leftSideValue.compareTo(rightSideValue)>=0);
default :
throw new Exception("Unknown operator type :"+operator);
}
}
}
/**
* This method splits an expression into leftside, operator and rightside.
*/
private static QASHTree createExpressionTree(List<QASHToken> expression) throws Exception {
QASHTree root = new QASHTree();
QASHTree currNode = root;
for (int i = 0; i < expression.size(); i++) {
QASHToken token = (QASHToken)expression.get(i);
switch (token.ttype) {
case LEFT_PARENTHESIS :
currNode.left = new QASHTree(currNode);
currNode = currNode.left;
break;
case RIGHT_PARENTHESIS : currNode = currNode.parent;
break;
case LESS_THAN :
case GREATER_THAN :
case LESS_THAN_EQ :
case GREATER_THAN_EQ :
case LOGICAL_AND :
case LOGICAL_OR :
case NOT_EQUAL_OPERATOR :
case EQUALITY_OPERATOR :
currNode.value=token;
currNode.right = new QASHTree(currNode);
currNode = currNode.right;
break;
case QASHToken.TT_WORD :
case QASHToken.TT_NUMBER :
case QASHToken.TT_STRING :
currNode.value=token;
currNode = currNode.parent;
break;
default : throw new Exception("Didn't expect:"+token);
}
}
return root;
}
/*--------- end the boolean expression handling routines ------------*/
/**
* Returns the index of the closing parenthesis matching the opening parenthesis
* passed in the parameter openingParenPos.
*/
public static int getClosingParenIndex(List<QASHToken> expr, int openingParenPos) throws Exception {
int lCount=1, rCount=0;
int i=openingParenPos+1;
QASHToken token;
while((lCount!=rCount)&&(i<expr.size())) {
token = ((QASHToken)expr.get(i));
if (token.ttype==RIGHT_PARENTHESIS) {
rCount++;
}
else
if (token.ttype==LEFT_PARENTHESIS) {
lCount--;
}
i++;
}
if (lCount==rCount) {
return (i-1);
}
else {
throw new Exception("Unmatched parenthesis in"+expr);
}
}
public String getTestName() {
String res = getProperty(TEST_NAME_TAG);
if (res == "") {
return backwardsCompat("TEST_NAME",TEST_NAME_TAG+" NOT DEFINED").toString();
}
return res;
}
public String getTestAuthor() {
String res = getProperty(TEST_AUTHOR_TAG);
if (res == "") {
return backwardsCompat("TEST_AUTHOR",TEST_AUTHOR_TAG+" NOT DEFINED").toString();
}
return res;
}
public String getTestBugInfo() {
return getProperty(TEST_BUGINFO_TAG,"");
}
public String getTestDescription() {
String res = getProperty(TEST_DESCRIPTION_TAG);
if (res == "") {
return backwardsCompat("TEST_DESCRIPTION",TEST_DESCRIPTION_TAG+" NOT DEFINED").toString();
}
return res;
}
private String getKeyWordsProperty() {
String res = getProperty(KEYWORD_TAG);
if (res == "") {
res = backwardsCompat("KEYWORDS","NOT FOUND").toString();
}
return res;
}
public String[] getKeyWords() {
return Utils.toStringArray(getKeyWordsProperty());
}
public String[] getIncludeList() {
return Utils.toStringArray(getProperty(INCLUDE_QASH_LIST).toString());
}
public String[] getPropertiesIncludeList() {
return Utils.toStringArray(getProperty(INCLUDE_PROPERTIES_LIST).toString());
}
public String[] getTraceList() {
return Utils.toStringArray(getProperty(INTERNAL_TRACE_LIST).toString());
}
public static final void main(String args[]) {
if (args.length<3) {
System.out.println("QASHParser command line interface");
System.out.println(" Useage : QASHParser <name> <propertiesFile> test1 test2 .. testn");
System.out.println(" name = offset in the QAT home directory to place the results");
System.out.println(" propertiesFile = the name of the properties or project file require to parse the test file");
System.out.println(" Useage : QASHParser <name> <propertiesFile> test1 test2 .. testn");
System.out.println(" Returns : zero if all the tests passed or non-zero if one or more failed");
System.exit(-1);
}
Properties def= new Properties(System.getProperties());
try {
def.load(new FileInputStream(new File(args[1])));
}
catch (Exception e) {
System.out.println("Error loading properties file :"+args[1]);
System.exit(-1);
}
try {
QASHParser parser = new QASHParser();
parser.setPrintStream(System.out,false);
parser.prepare(args[1]);
parser.setEvaluationMode(false);
int currResult=0;
int resultHolder=0;
for (int i = 2; i < args.length; i++) {
parser.setTestPath(args[i]);
parser.setProperties(new Properties(def));
try {
currResult = parser.parseFile();
}
catch (Exception e) {
log.severe("Parser error running :"+args[i]);
currResult = -1;
}
if (currResult!=0) {
resultHolder = currResult;
log.severe(">>>>>>> Failed :"+currResult);
}
else {
log.severe(">>>>>>> Passed :"+currResult);
}
}
log.info("Finished running :"+resultHolder);
System.exit(resultHolder);
}
catch (Exception e) {
e.printStackTrace();
}
}
public void setStatusLabel(JLabel status) {
this.parserStatus = status;
}
private void setStatus(int newStatus) {
currQASHStatus = newStatus;
}
private int getStatus() {
return currQASHStatus;
}
private boolean isStatusReported() {
return statusReported;
}
private void setStatusReported(boolean r) {
statusReported = r;
}
private void setStatusText(String s) {
if (!inEvaluationMode())
parserStatus.setText(s);
}
private void setStatusText(String s1, String s2) {
if (!inEvaluationMode())
parserStatus.setText(s1+LEFT_PARENTHESIS+Utils.trimFileName(s2,20)+RIGHT_PARENTHESIS);
}
}