/*
* Created on Nov 15, 2005
*
* Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved.
*/
package jsystem.framework.scenario;
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jsystem.extensions.handlers.UIEventHandler;
import jsystem.extensions.handlers.ValidationHandler;
import jsystem.extensions.report.html.HtmlCodeWriter;
import jsystem.framework.FrameworkOptions;
import jsystem.framework.JSystemProperties;
import jsystem.framework.ParameterProperties;
import jsystem.framework.TestProperties;
import jsystem.framework.report.ListenerstManager;
import jsystem.framework.report.RunnerListenersManager;
import jsystem.framework.scenario.Parameter.ParameterType;
import jsystem.framework.scripts.ScriptEngine;
import jsystem.framework.scripts.ScriptExecutor;
import jsystem.framework.scripts.ScriptsEngineManager;
import jsystem.runner.loader.LoadersManager;
import jsystem.utils.DateUtils;
import jsystem.utils.StringUtils;
import jsystem.utils.XmlUtils;
import junit.framework.SystemTest;
import junit.framework.Test;
import junit.framework.TestResult;
import org.springframework.util.ObjectUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* This class represents a single test in the runner. <br>
* The class holds all the data related to a runner test in the scenario. -
* Properties = test properties read from xml file. Parameters = hashmap of the
* test parameters. These parameters are fetched from an instance of the test
* class using introspection. Documentation = user test documentation. read from
* xml file under "user-Doc" attribute. updated through UI. Comment = user
* comment. read from xml file. modified through UI right-click menu testJavadoc
* = method javadoc - read from file.
*
*
* RunnerTest life-cycle: in order to improve runner performance test parameters
* are loaded in introspection only on demand (when user wants to se test
* parameters in the runner, before running test in run mode 2/4, before saving
* test in file system again)
*
* Test data is divided to three types: Test parameters (saved in Parameters
* map, fetched by introspecting test class and understanding it's setters and
* getters) a special parameter is the fixture parameter. It is not visible to
* the runner's user. it is for internal usage. Also the value of the fixture is
* saved directly in the task of the test as sysproperty so it won't be possible
* to override fixture name. Test description data: comment,meaningful name,
* Documentation, javadoc,isDisabled in the RunnerTest class these are saved in
* class members. javadoc and meaningful name are fetched by introspecting the
* class. comment and documentation are fetched from ant xml. isDisabled - when
* is disabled is true, jsystem task doesn't activate the test.
*
* On adding new test to scenario a unique ID will be added. This ID will
* uniquely identify the test. Changing the test properties will not change the
* ID.
*
* Test in ant XML: please see Scenario class documentation to understand how
* test in saved in ant xml file. as described above, the data that is saved in
* the ant script file is test parameters, user documentation and comment. this
* data is saved as ant properties and passed to the jsystem ant task as
* sysproperty.
*
* test properties are saved in two places: 1. test target (default value for
* test parameters) 2. in the scenario that invokes test's scenario (if there is
* one)
*
* Parameters Include/Exclude & sorting:<br>
* -------------------------------------<br>
* the user can choose which parameters are visible for which test.<br>
* this means the chosen parameters will be visible on the parameters tab and
* also on the HTML report this can be done by using the proper annotation in
* the test's javadoc.<br>
* - "@params.exclude" <parameters> - comma or space seperated, indicates using
* all parameters in class apart of excluded ones.<br>
* -"@params.include" <parameters> - comma or space seperated, indicates using
* only these parameters.<br>
* NOTE: if both annotations are present. the first one on the javadoc is
* chosen.<br>
* - sectionOrder = String array which specifies the ordering of parameters
* sections.<br>
* - sort = PresentationDefinitions member which holds all the definitions for
* the sorting (ascending/descending , by Alph-betic order/type....)
*
*/
public class RunnerTest implements JTest, UIHandler {
protected static Logger log = Logger.getLogger(RunnerTest.class.getName());
public static final int STAT_NOT_RUN = 0;
public static final int STAT_RUNNING = 1;
public static final int STAT_FAIL = 2;
public static final int STAT_ERROR = 3;
public static final int STAT_SUCCESS = 4;
public static final int STAT_WARNING = 5;
protected static final int INCLUDE = 0;
protected static final int EXCLUDE = 1;
protected static final int NO_INCLUDE_OR_EXCLUDE = 2;
public static final String INCLUDE_PARAMS_STRING = "params.include";
public static final String EXCLUDE_PARAMS_STRING = "params.exclude";
protected static String testJavadoc = "";
protected String className;
protected String methodName;
String associatedFixtureClassName;
private String[] sectionOrder = null;
// kept in test instance to decide on parameters order when needed.
private String[] paramsOrder;
/*
* Holds parameters values as fetched from scenario's XML.
*/
protected Properties properties = new Properties();
/*
* Map of Parameter which holds test parameters and default values as
* fetched from test class by introspection.
*/
protected HashMap<String, Parameter> parameters = null;
protected Test test;
int status = STAT_NOT_RUN;
protected String testId = null;
JTestContainer parent = null;
private PresentationDefinitions sort = null;
protected String codeMeaningfulName = null;
protected String meaningfulName = null;
protected boolean meaningfulNameShouldBeSaved = false;
private String[] groups = null;
protected String includeParamsStringAnnotation = null;
protected String excludeParamsStringAnnotation = null;
protected String significantParamsStringAnnotation = null;
private boolean failureOccurred = false;
protected String uuid = null;
protected ArrayList<ValidationError> validationErrors = new ArrayList<ValidationError>();
private static final Pattern SCENARIO_PARAMETERIZATION_PATTERN = Pattern.compile("\\$\\{(.*?)\\}");
public RunnerTest(String className, String methodName) {
this.className = className;
this.methodName = methodName;
uuid = getRandomUUID();
}
public RunnerTest cloneTest() throws Exception {
RunnerTest test = new RunnerTest(className, methodName);
// Clone the properties as well
test.setProperties((Properties) getProperties().clone());
return test;
}
/**
* Appends test + test settings to XML.
*/
public void addTestsXmlToRoot(Document doc, Integer[] indexes) {
Element target = doc.createElement(RunningProperties.ANT_TARGET);
target.setAttribute("name", testId);
// add the properties with test parameters values
addAntPropertiesToTarget(target, doc);
/*
* Create and add the jsystem task tag and attributes
*/
Element jsystem = doc.createElement("jsystem");
appendPropertiesToJSystemTask(jsystem, doc);
target.appendChild(jsystem);
// Add test to root as target
Element root = doc.getDocumentElement();
root.appendChild(target);
}
/**
* Appends test + test settings to XML.
*/
public Element addExecutorXml(Element targetScenario, Document parentDoc) {
// adding antcall to the target from the execute scenario target
Element antCall = parentDoc.createElement("antcallback");
antCall.setAttribute(RunningProperties.ANT_TARGET, testId);
// adding return of all relevant properties
// TODO: return only output properties - split the list !
filterProperties(properties);
// TODO: we might want to change it
// to use full id in the future - String keyPrefix = getFullTestId() +
// "/";
// Set the return attribute to get the properties back
ArrayList<String> returnArray = new ArrayList<String>();
String[] returnParameters = getReturnParameters();
if (returnParameters != null) {
for (String returnParameter : returnParameters) {
returnArray.add(returnParameter);
}
if (!returnArray.isEmpty()) {
String returnString = returnArray.toString();
returnString = (String) returnString.subSequence(1, returnString.length() - 1);
antCall.setAttribute("return", returnString);
}
}
targetScenario.appendChild(antCall);
return antCall;
}
/**
* Adds test properties to the target which calls
*/
public void addAntPropertiesToTarget(Element el, Document doc) {
filterProperties(properties);
Scenario r = (Scenario) getRoot();
ScenarioHelpers.updateTestProperties(this, r.getName(), true);
Properties p = new Properties();
if (meaningfulNameShouldBeSaved) {
p.setProperty(RunningProperties.MEANINGFUL_NAME_TAG, meaningfulName == null ? "" : meaningfulName);
}
p.setProperty(RunningProperties.UI_SETTINGS_TAG, sort == null ? "" : sort.toAntProperty());
ScenarioHelpers.setTestInnerProperty(getFullUUID(), r.getName(), p, false);
}
private void appendPropertiesToJSystemTask(Element jsystemTask, Document parentDoc) {
jsystemTask.setAttribute("showoutput", "true");
Element testElement = parentDoc.createElement("test");
testElement.setAttribute("name", className + "." + methodName);
addPrivateTags(parentDoc, jsystemTask);
// remove properties that we got from xml but
// should be returned from class members
filterProperties(properties);
if (!StringUtils.isEmpty(associatedFixtureClassName)) {
Element p = parentDoc.createElement("sysproperty");
p.setAttribute("key", RunningProperties.PARAM_PREFIX + RunningProperties.FIXTURE_PROPERTY_NAME);
p.setAttribute("value", associatedFixtureClassName);
jsystemTask.appendChild(p);
}
Element p = parentDoc.createElement("sysproperty");
p.setAttribute("key", RunningProperties.UUID_TAG);
p.setAttribute("value", getUUID());
jsystemTask.appendChild(p);
p = parentDoc.createElement("sysproperty");
p.setAttribute("key", RunningProperties.UUID_PARENT_TAG);
p.setAttribute("value", "${" + RunningProperties.UUID_PARENT_TAG + "}.${" + RunningProperties.UUID_TAG + "}");
jsystemTask.appendChild(p);
p = parentDoc.createElement("sysproperty");
p.setAttribute("key", RunningProperties.PARENT_NAME);
p.setAttribute("value", "${" + RunningProperties.PARENT_NAME + "}.${ant.project.name}");
jsystemTask.appendChild(p);
jsystemTask.appendChild(testElement);
}
/**
* Creates a RunnerTest instance from ant XML.
*
* callingTarget: the target which invokes the scenario which contains this
* test. Could be null if the scenario of the test is root scenario.
* testTarget: the target which invokes the jsystem task of this test
*
*/
public static RunnerTest fromElement(Element callingTarget, Element testTarget, Test test, JTestContainer parent)
throws Exception {
Element testElement = XmlUtils.getElement("test", 0, testTarget);
String tname = testElement.getAttribute("name");
String tid = testTarget.getAttribute("name");
String className = null;
String methodName = null;
if (tname != null) {
int dotIndex = tname.lastIndexOf('.');
className = tname.substring(0, dotIndex);
methodName = tname.substring(dotIndex + 1);
}
if (methodName == null || className == null) {
return null;
}
NodeList list = testTarget.getElementsByTagName("sysproperty");
boolean scriptNode = false;
boolean systemObjectOperationNode = false;
String scriptTag = null;
String scriptPath = null;
for (int i = 0; i < list.getLength(); i++) {
Node n = list.item(i);
if (!(n instanceof Element)) {
continue;
}
Element prop = (Element) n;
if (RunningProperties.SCRIPT_TAG.equals(prop.getAttribute("key"))) {
scriptNode = true;
scriptTag = prop.getAttribute("value");
break;
} else if (RunningProperties.SYSTEM_OBJECT_OPERATION.equals(prop.getAttribute("key"))) {
systemObjectOperationNode = true;
break;
}
}
if (scriptNode || systemObjectOperationNode) {
for (int i = 0; i < list.getLength(); i++) {
Node n = list.item(i);
if (!(n instanceof Element)) {
continue;
}
Element prop = (Element) n;
if (RunningProperties.SCRIPT_PATH.equals(prop.getAttribute("key"))) {
scriptPath = prop.getAttribute("value");
break;
}
}
}
RunnerTest rTest;
if (scriptNode) {
ScriptEngine engine = ScriptsEngineManager.getInstance().findExecutor(className);
if (engine == null) {
// the user will get an error indication but he will
return null;
}
ScriptExecutor executor = engine.getExecutor(scriptTag);
if (executor == null) {
return null;
}
executor.configFilePath(scriptPath);
rTest = new RunnerScript(executor);
} else if (systemObjectOperationNode) {
rTest = RunnerSOTest.initFromNodeList(list);
} else {
rTest = new RunnerTest(className, methodName);
}
rTest.setParent(parent);
rTest.setTest(test);
rTest.setTestId(tid);
Element myTarget = XmlUtils.getElement("jsystem", 0, testTarget);
rTest.setUUID(loadUuid(myTarget));
boolean is49 = isScenarioParameterizationAntFile(testTarget);
ArrayList<Element> propertiesToUpdateWith;
// if we are working with a scenario that was created with TAS 4.9 then
// the values should be fetched from test target or parent of parent
// scenario target properties
// otherwise it is fetched directly from the JSystem task
if (is49) {
// merge the properties for the parent calling scenario target with
// the properties
// of the test target.
// give priority to parent scenario values.
ArrayList<Element> testTargetProperties = XmlUtils.getElementsByTag("property", testTarget);
if (callingTarget != null) {
propertiesToUpdateWith = XmlUtils.getElementsByTag("property", callingTarget);
} else {
propertiesToUpdateWith = new ArrayList<Element>();
}
propertiesToUpdateWith = XmlUtils.mergeByAttrib(propertiesToUpdateWith, testTargetProperties, "name");
} else {
propertiesToUpdateWith = XmlUtils.getElementsByTag("sysproperty", testTarget);
}
setTestProperties(parent, tid, className, methodName, rTest, is49, propertiesToUpdateWith);
return rTest;
}
/**
* load the Unique test Id from the XML system property<br>
* if no value is found, generate a new one otherwise
*
* @param target
* the test target element
* @return the unique id String
*/
private static String loadUuid(Element target) {
ArrayList<Element> elements = XmlUtils.getChildElementsByTag("sysproperty", target);
Element uuidProp = null;
for (Element e : elements) {
String key = e.getAttribute("key");
if (key.equals(RunningProperties.UUID_TAG)) {
uuidProp = e;
break;
}
}
if (uuidProp != null) {
return uuidProp.getAttribute("value");
}
log.fine("RunnerTest did not have a UUID, Generating a new one");
return getRandomUUID();
}
/**
* create a random Unique ID
*
* @return
*/
public static String getRandomUUID() {
return UUID.randomUUID().toString();
}
private static void setTestProperties(JTest parent, String tid, String className, String methodName,
RunnerTest rTest, boolean is49, ArrayList<Element> propertiesToUpdateWith) throws Exception {
Scenario root = (Scenario) rTest.getRoot();
String fullUUID = rTest.getFullUUID();
rTest.initTestProperties();
Properties currentProperties = new Properties();
String include = rTest.getIncludeParamsStringAnnotation();
String exclude = rTest.getExcludeParamsStringAnnotation();
if ((include == null) && (exclude == null)) {
include = HtmlCodeWriter.getInstance().getMethodAnnotation(className, methodName, INCLUDE_PARAMS_STRING);
exclude = HtmlCodeWriter.getInstance().getMethodAnnotation(className, methodName, EXCLUDE_PARAMS_STRING);
}
int annotation = compareIncludeAndExclude(include, exclude);
String name;
for (Element prop : propertiesToUpdateWith) {
String key;
if (is49) {
key = prop.getAttribute("name");
} else {
key = prop.getAttribute("key");
}
String value = prop.getAttribute("value");
if (StringUtils.isEmpty(key)) {
continue;
}
String preFix = ScenarioHelpers.getFirstScenarioAncestor(parent).getName().trim() + "/" + tid + "/";
// if it is a property of another test in the scenario
if (!key.startsWith(preFix) && is49) {
continue;
}
// trim scenario/testid prefix
if (is49) {
key = key.substring(preFix.length());
} else {
if (key.startsWith(RunningProperties.PARAM_PREFIX)) {
key = key.substring(RunningProperties.PARAM_PREFIX.length());
}
}
if (key.equals(RunningProperties.DOCUMENTATION_TAG)) {
rTest.setDocumentation(value);
continue;
}
if (key.equals(RunningProperties.COMMENT_TAG)) {
rTest.setTestComment(value);
continue;
}
if (key.equals(RunningProperties.UI_SETTINGS_TAG)) {
rTest.sort = PresentationDefinitions.fromAntProperty(value);
continue;
}
if (key.equals(RunningProperties.FIXTURE_PROPERTY_NAME)) {
rTest.setFixture(value);
continue;
}
if (key.equals(RunningProperties.PARENT_NAME)) {
continue;
}
name = lowerFirstLetter(key);
if (annotation == NO_INCLUDE_OR_EXCLUDE
|| (annotation == INCLUDE && checkParamsIncludeExclude(include, name))
|| (annotation == EXCLUDE && (!checkParamsIncludeExclude(exclude, name)))) {
currentProperties.put(key, value);
}
}
String orderStr = ScenarioHelpers.getTestProperty(fullUUID, root.getName(), RunningProperties.UI_SETTINGS_TAG);
if (orderStr != null) {
rTest.sort = PresentationDefinitions.fromAntProperty(orderStr);
}
String fixture = ScenarioHelpers.getTestProperty(fullUUID, root.getName(),
RunningProperties.FIXTURE_PROPERTY_NAME);
if (fixture != null) {
rTest.setFixture(fixture);
}
rTest.setParent((JTestContainer) parent);
Properties fromAllScenarios = null;
if (JSystemProperties.getInstance().getPreferenceOrDefault(FrameworkOptions.CACHE_SCENARIO_PROPERTIES)
.equals("true")) {
fromAllScenarios = ScenarioHelpers.getAllTestPropertiesUpTo(rTest, null, false);
} else {
fromAllScenarios = ScenarioHelpers.getAllTestPropertiesFromAllScenarios(rTest);
}
currentProperties.putAll(fromAllScenarios);
ScenarioHelpers.loadTestProperties(rTest, currentProperties);
rTest.setProperties(currentProperties);
rTest.loadMeaningfulName(true);
}
private void loadMeaningfulName(boolean include) {
Scenario upto = include ? null : getRoot();
String meaningful = null;
if (JSystemProperties.getInstance().getPreferenceOrDefault(FrameworkOptions.CACHE_SCENARIO_PROPERTIES)
.equals("true")) {
meaningful = ScenarioHelpers.getAllTestPropertiesUpTo(this, upto, false).getProperty(
RunningProperties.MEANINGFUL_NAME_TAG);
} else {
meaningful = ScenarioHelpers.getAllTestPropertiesUpTo(this, upto, true).getProperty(
RunningProperties.MEANINGFUL_NAME_TAG);
}
this.meaningfulName = meaningful;
}
/**
* returns true if this is a scenario which includes scenario
* parameterization (was created with TAS 4.9). it checks whether the value
* of the sysproperty value exists in test target property. If so, this
* means this is a scenario file created with 4.9
*/
private static boolean isScenarioParameterizationAntFile(Element testTarget) throws Exception {
ArrayList<Element> list = XmlUtils.getElementsByTag("sysproperty", testTarget);
Map<String, Element> map = XmlUtils.mapFromArrayListByAttribute(
XmlUtils.getElementsByTag("property", testTarget), "name");
if (list.size() == 0) {
return true;
}
// skip fixture since it gets it's value directly and not from
// an ant property
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getAttribute("key")
.equals(RunningProperties.PARAM_PREFIX + RunningProperties.FIXTURE_PROPERTY_NAME)
|| list.get(i).getAttribute("key").equals(RunningProperties.UUID_TAG)
|| list.get(i).getAttribute("key").equals(RunningProperties.UUID_PARENT_TAG)) {
continue;
}
String value = list.get(i).getAttribute("value");
Matcher m = SCENARIO_PARAMETERIZATION_PATTERN.matcher(value);
if (m.find()) {
String key = m.group(1);
if (map.get(key) != null) {
return true;
}
}
}
return false;
}
/**
* converts the test properties to a String format<br>
* if there are references they will be replaced first
*
* @return a String of parameters , space separated
*/
public String getPropertiesAsString() {
Properties clone = (Properties) properties.clone();
clone.remove("disable");
Properties fields = getAllInnerFields();
Enumeration<Object> keys = fields.keys();
while (keys.hasMoreElements()) {
clone.remove(keys.nextElement());
}
try {
return ParameterUtils.propertiesToString(clone);
} catch (Exception e) {
log.warning("Failed converting test parameters to string " + e.getMessage());
return "";
}
}
/**
* get this test Test. If test is null returns a <code>TestLoadError</code>
* object which is shown to user
*/
public Test getTest() {
if (test == null) {
TestLoadError testLoadError = new TestLoadError();
testLoadError.setClassName(className);
testLoadError.setName("testError");
return testLoadError;
}
((SystemTest) test).setFullUUID(getFullUUID());
return test;
}
/**
* Loads test class and, and initializes test's meaningful name.
*/
public void load() throws Exception {
loadTestClass();
initTestProperties();
}
public void loadParametersAndValues() {
getTestParameters();
setParameters();
updateProperties();
}
/**
* find a parameter type by it's name
*
* @param name
* @return
*/
public ParameterType getParameterType(String name) {
if (parameters == null || parameters.size() == 0) {
loadParameters();
}
Object[] arrayObjects = parameters.values().toArray();
for (int index = 0; index < arrayObjects.length; index++) {
Parameter parameter = (Parameter) arrayObjects[index];
if (parameter.getName().equals(name)) {
return parameter.getType();
}
}
return null;
}
private void updateProperties() {
for (Parameter parameter : parameters.values()) {
if (parameter.getValue() == null) {
continue;
}
properties.setProperty(parameter.getName(), parameter.getStringValue());
}
}
public void loadParametersAndValuesAndUpdateTestClass() {
loadParametersAndValues();
setTestClassParameters();
}
/**
* Invoke the test case handleUiEvent method.
*
* @return True if the testCase is from type handleUiEvent and the
* invocation succeeded.
*/
public boolean handleUIEvent(Parameter[] params) {
HashMap<String, Parameter> map = new HashMap<String, Parameter>();
for (Parameter currentParameter : params) {
if (currentParameter.isAsOptions()) {
updateOptions(null, currentParameter);
}
map.put(currentParameter.getName(), currentParameter);
}
try {
if (getTest() instanceof UIEventHandler) {
((UIEventHandler) getTest()).handleUIEvent(map, getMethodName());
return true;
}
} catch (Exception e) {
log.log(Level.WARNING, "Failed executing handle ui event on class: " + getTest().getClass(), e);
}
return false;
}
public ValidationError[] validate(Parameter[] params) {
HashMap<String, Parameter> map = new HashMap<String, Parameter>();
for (Parameter currentParameter : params) {
map.put(currentParameter.getName(), currentParameter);
}
try {
if (getTest() instanceof ValidationHandler) {
return ((ValidationHandler) getTest()).validate(map, getMethodName());
} else {
log.fine("validate was not found");
}
} catch (Exception e) {
log.log(Level.WARNING, "Failed executing validate method", e);
}
return null;
}
private void loadTestClass() throws Exception {
if (test != null) {
return;
}
ClassLoader loader = LoadersManager.getInstance().getLoader();
Class<?> testClass;
Object o;
testClass = loader.loadClass(className);
if (Test.class.isAssignableFrom(testClass)) {
// JUnit 3 style test
Constructor<?> constract;
try {
constract = testClass.getConstructor(new Class[0]);
o = constract.newInstance(new Object[0]);
if (o instanceof SystemTest) {
((SystemTest) o).setName(methodName);
}
} catch (Exception ex) {
constract = testClass.getConstructor(new Class[] { String.class });
o = constract.newInstance(new Object[] { methodName });
}
if (o instanceof SystemTest && parent != null) {
((SystemTest) o).setFullUUID(getFullUUID());
}
test = (Test) o;
}
}
/**
*/
public void initTestProperties(boolean withParameters) throws Exception {
loadTestClass();
TestProperties testProperties = getTestProperties();
if (testProperties != null) {
// TestProperties tp = m.getAnnotation(TestProperties.class);
codeMeaningfulName = StringUtils.isEmpty(testProperties.name()) ? null : testProperties.name();
includeParamsStringAnnotation = null;
if (!checkIsIgnore(testProperties.paramsInclude())) {
StringBuilder sb = new StringBuilder("");
for (String param : testProperties.paramsInclude()) {
sb.append(param).append(" ");
}
includeParamsStringAnnotation = sb.toString();
}
groups = testProperties.group();
if (groups != null && groups.length == 0) {
groups = null;
}
excludeParamsStringAnnotation = null;
if (!checkIsIgnore(testProperties.paramsExclude())) {
StringBuilder sb = new StringBuilder("");
for (String param : testProperties.paramsExclude()) {
sb.append(param).append(" ");
}
excludeParamsStringAnnotation = sb.toString();
}
significantParamsStringAnnotation = null;
if (!checkIsIgnore(testProperties.mandatoryFields())) {
StringBuffer stringBuffer = new StringBuffer("");
for (String param : testProperties.mandatoryFields()) {
stringBuffer.append(param).append(" ");
}
significantParamsStringAnnotation = stringBuffer.toString();
}
if (withParameters) {
codeMeaningfulName = processTestName(codeMeaningfulName);
}
if (StringUtils.isEmpty(codeMeaningfulName)) {
codeMeaningfulName = null;
}
}
}
private TestProperties getTestProperties() {
try {
Method method = test.getClass().getMethod(methodName, new Class[0]);
if (method.isAnnotationPresent(TestProperties.class)) {
return method.getAnnotation(TestProperties.class);
}
return null;
} catch (Exception e) {
return null;
}
}
protected String processTestName(String originalName) {
if (originalName != null && !originalName.equals("")) {
ArrayList<String> listOfParams = getMeaningfulNameParameters(originalName);
Map<String, String> map = getValueForParameters(listOfParams);
for (String key : map.keySet()) {
String value = map.get(key);
String keyFirstCharUpperCase = StringUtils.firstCharToUpper(key);
originalName = StringUtils.replace(originalName, "${" + key + "}", value);
originalName = StringUtils.replace(originalName, "${" + keyFirstCharUpperCase + "}", value);
}
}
return originalName;
}
/**
* check if the params include\exclude has no value
*
* @param toCheck
* the String array from the annotation
* @return False if no value was set
*/
private boolean checkIsIgnore(String[] toCheck) {
return (toCheck.length == 1 && TestProperties.NOT_DEFINED.equals(toCheck[0]));
}
/**
* Returns tests return parameter. Return parameter is a parameter that is
* returned by the test. Return parameters are regular test parameters, at
* the end of test execution, the platform fetches parameter's value and
* creates an ant property with parameter name and value. If parameter
* already exists, it is overridden. To define a parameter to be a return
* parameter, use the {@link TestProperties#returnParam()} annotation.
*/
public String[] getReturnParameters() {
Method method;
try {
method = test.getClass().getMethod(methodName, new Class[0]);
} catch (Exception e) {
return new String[0];
}
if (method.isAnnotationPresent(TestProperties.class)) {
TestProperties testProperties = method.getAnnotation(TestProperties.class);
// Change first letter to uppercase
// Currently parameters are shown only with first upper case
// even if they are lower case in the code.
// Note - thisParam and ThisParam can't exist together
String[] params = testProperties.returnParam();
ArrayList<String> paramsToReturn = new ArrayList<String>();
for (int i = 0; i < params.length; i++) {
params[i] = StringUtils.firstCharToUpper(params[i]);
paramsToReturn.add(params[i]);
}
return paramsToReturn.toArray(new String[0]);
}
return null;
}
private ArrayList<String> getMeaningfulNameParameters(String name) {
ArrayList<String> result = new ArrayList<String>();
Matcher matcher = ParametersManager.PARAMETER_PATTERN.matcher(name);
while (matcher.find()) {
result.add(StringUtils.firstCharToLower(matcher.group(1)));
}
return result;
}
private Map<String, String> getValueForParameters(ArrayList<String> parameters) {
HashMap<String, String> map = new HashMap<String, String>();
for (String key : parameters) {
map.put(key, getValueForParameter(key));
}
return map;
}
protected String getValueForParameter(String parameter) {
parameter = StringUtils.firstCharToUpper(parameter);
if (properties.get(parameter) != null) {
return properties.getProperty(StringUtils.firstCharToUpper(parameter));
}
Method getter = null;
try {
getter = test.getClass().getMethod("get" + parameter, new Class[0]);
} catch (Throwable t) {
}
if (getter == null) {
try {
getter = test.getClass().getMethod("is" + parameter, new Class[0]);
} catch (Throwable t) {
}
}
if (getter == null) {
return "${" + parameter + "}";
}
try {
return getter.invoke(test, new Object[0]).toString();
} catch (Throwable t) {
return "${" + parameter + "}";
}
}
/**
* Return a parameters that should be visible by user Currently fixture name
* is the only parameter which should not be visible.
*/
public Parameter[] getVisibleParamters() {
return getVisibleParamters(false);
}
/**
* Return a parameters that should be visible by user Currently fixture name
* is the only parameter which should not be visible.
*/
public Parameter[] getVisibleParamters(boolean recursively) {
if (parameters == null) {
loadParametersAndValues();
}
Parameter fn = getTestParameters().get(RunningProperties.FIXTURE_PROPERTY_NAME);
if (fn == null) {
return getParameters();
}
try {
parameters.remove(RunningProperties.FIXTURE_PROPERTY_NAME);
Parameter[] par = getParameters();
Parameter[] parToReturn = new Parameter[par.length];
System.arraycopy(par, 0, parToReturn, 0, par.length);
return parToReturn;
} finally {
parameters.put(fn.getName(), fn);
}
}
/**
*/
public void initTestProperties() {
try {
initTestProperties(true);
} catch (Throwable e) {
log.fine("Problem initiating TestProperties annotation for test " + getMethodName());
}
}
/**
* checks if an include/exclude is to be done. assumes the testJavadoc was
* already initialized
*
* @param include
* the include string array
* @param exclude
* the exclude string array
* @return NO_INCLUDE_OR_EXCLUDE / INCLUDE / EXCLUDE
*/
protected static int compareIncludeAndExclude(String include, String exclude) {
if (include != null) {
return INCLUDE;
}
if (exclude != null) {
return EXCLUDE;
}
return NO_INCLUDE_OR_EXCLUDE;
}
/**
* lower case the first letter of a string - for set methods
*
* @param name
* the parameter with the upper case name
* @return the parameter with the first letter lower-cased
*/
protected static String lowerFirstLetter(String name) {
return StringUtils.firstCharToLower(name);
}
/**
* creates the parameters HashMap for the parameters tab in the UI uses the
* class and tests javadocs.
*
* possible notation: ------------------ -
*
* @exclude - excluding parameters - extended explenation at class javadoc -
* @include - including parameters - extended explenation at class javadoc
*
* special supported method names: -------------------------------
* - set<Parameter> = enables a parameter value setting -
* get<Parameter> = enables a parameter value getting -
* get<Parameter>Options = enables a selection menu with the
* specified options array in the method.
*/
protected void loadParameters() {
parameters = new HashMap<String, Parameter>();
if (test == null) {
log.warning("test class could not be loaded. class=" + getClassName() + " method=" + getMethodName());
return;
}
String include = includeParamsStringAnnotation;
String exclude = excludeParamsStringAnnotation;
String important = significantParamsStringAnnotation;
if (include == null && exclude == null) {
exclude = HtmlCodeWriter.getInstance().getMethodAnnotation(className, methodName, EXCLUDE_PARAMS_STRING);
include = HtmlCodeWriter.getInstance().getMethodAnnotation(className, methodName, INCLUDE_PARAMS_STRING);
}
if (important == null) {
important = "";
}
int annotation = compareIncludeAndExclude(include, exclude);
for (Method method : test.getClass().getMethods()) {
String methodName = method.getName();
if (methodName.equals("setUp") || methodName.equals("setFixture") || methodName.equals("setFixtureName")
|| methodName.equals("setTearDownFixture") || methodName.equals("setName")
|| methodName.equals("setTestDocumentation") || methodName.equals("setPass")
|| methodName.equals("setTestInfo") || methodName.equals("setTestId")
|| methodName.equals("setParentFixture") || methodName.equals("setFullUUID")) {
continue;
}
/**
* Go over all the set methods
*/
if (methodName.toLowerCase().startsWith("set") && methodName.length() > 3) {
Class<?>[] parametersType = method.getParameterTypes();
/**
* work only with single parameter setter
*/
if (parametersType.length != 1) {
log.log(Level.FINE, "Number of setter parameter is not 1 for: " + methodName);
continue;
}
Class<?> type = parametersType[0];
String paramName = methodName.substring(3);
Parameter currentParameter = new Parameter();
currentParameter.setName(paramName);
currentParameter.setSetMethod(method);
/**
* Init the getter method if exits
*/
Method getter = null;
Object defaultValue = null;
try {
try {
getter = test.getClass().getMethod("get" + paramName, new Class[0]);
} catch (Throwable tt) {
// ignored
}
if (getter == null) {
try {
getter = test.getClass().getMethod("is" + paramName, new Class[0]);
} catch (Throwable tt) {
// ignored
}
}
/**
* If getter return type not match set the getter to null
*/
if (getter != null) {
if (!getter.getReturnType().equals(type)) {
getter = null;
log.warning("Getter return type not match for: " + methodName);
} else {
currentParameter.setGetMethod(getter);
try {
defaultValue = getter.invoke(test, new Object[0]);
} catch (Exception e) {
log.warning("Fail to invoke method: " + methodName);
}
}
} else {
log.warning("Parameter " + paramName + " doesn't have a getter");
}
} catch (Throwable throwable) {
// ignored
}
currentParameter.setMandatory(important.toLowerCase().indexOf(paramName.toLowerCase()) >= 0);
updateOptions(type, currentParameter);
// first check if this method uses provider
UseProvider useProvider = method.getAnnotation(UseProvider.class);
if (useProvider != null) { // will use provider
ParameterProvider provider;
try {
String[] args = useProvider.config();
provider = (ParameterProvider) LoadersManager.getInstance().getLoader()
.loadClass(useProvider.provider().getName()).newInstance();
provider.setProviderConfig(args);
} catch (Exception e) {
log.log(Level.WARNING, "Fail to create new instance of provider", e);
continue;
}
currentParameter.setType(ParameterType.USER_DEFINED);
currentParameter.setProvider(provider);
currentParameter.setParamClass(type);
} else {
if (type.equals(Date.class)) {
currentParameter.setType(ParameterType.DATE);
} else if (type.equals(File.class)) {
currentParameter.setType(ParameterType.FILE);
} else if (type.equals(String.class)) {
currentParameter.setType(ParameterType.STRING);
} else if (type.equals(String[].class)) {
currentParameter.setType(ParameterType.STRING_ARRAY);
if (currentParameter.isAsOptions()) {
ParameterProvider provider;
try {
provider = (ParameterProvider) getClass()
.getClassLoader()
.loadClass(
"jsystem.extensions.paramproviders.StringArrayOptionsParameterProvider")
.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
currentParameter.setProvider(provider);
currentParameter.setParamClass(type);
}
} else if (type.equals(Integer.TYPE)) {
currentParameter.setType(ParameterType.INT);
} else if (type.equals(Boolean.TYPE)) {
currentParameter.setType(ParameterType.BOOLEAN);
} else if (type.equals(Long.TYPE)) {
currentParameter.setType(ParameterType.LONG);
} else if (type.equals(Float.TYPE)) {
currentParameter.setType(ParameterType.FLOAT);
} else if (type.equals(Double.TYPE)) {
currentParameter.setType(ParameterType.DOUBLE);
} else if (type.equals(Short.TYPE)) {
currentParameter.setType(ParameterType.SHORT);
} else if (type.isEnum()) {
currentParameter.setType(ParameterType.ENUM);
currentParameter.setAsOptions(true);
/*
* convert the enums options into string array
*/
if (defaultValue != null) {
defaultValue = ((Enum<?>) defaultValue).toString();
}
Object[] enumConstants = type.getEnumConstants();
String[] enumStrings = new String[enumConstants.length];
HashMap<String, String> enumStringsAndNames = new HashMap<String, String>();
for (int ii = 0; ii < enumConstants.length; ii++) {
String name = ((Enum<?>) enumConstants[ii]).name();
String toString = ((Enum<?>) enumConstants[ii]).toString();
enumStrings[ii] = toString;
enumStringsAndNames.put(toString, name);
}
currentParameter.setOptions(enumStrings);
currentParameter.setEnumStringsAndNames(enumStringsAndNames);
} else {
log.fine("Unknown parameter type: " + type.getName() + " for: " + paramName);
continue;
}
}
/*
* init the value and the default value
*/
currentParameter.setDefaultValue(defaultValue);
currentParameter.setValue(defaultValue);
try {
String doc = null;
Class<?> cls = test.getClass();
while (true) {
doc = HtmlCodeWriter.getInstance().getMethodJavaDoc(cls.getName(), methodName);
if (doc != null) {
break;
}
cls = cls.getSuperclass();
if (cls == null) {
doc = "";
break;
}
}
currentParameter.setDescription(doc);
if (method.isAnnotationPresent(ParameterProperties.class)) {
ParameterProperties pp = method.getAnnotation(ParameterProperties.class);
if (!StringUtils.isEmpty(pp.description())) {
currentParameter.setDescription(pp.description());
}
if (!StringUtils.isEmpty(pp.section())) {
currentParameter.setSection(pp.section());
}
}
} catch (Exception e) {
log.log(Level.WARNING, "Fail to get Doc of Param " + currentParameter.getName());
}
String name = lowerFirstLetter(currentParameter.getName());
if (annotation == NO_INCLUDE_OR_EXCLUDE) {
parameters.put(currentParameter.getName(), currentParameter);
} else if (annotation == INCLUDE) {
if (checkParamsIncludeExclude(include, name)) {
parameters.put(currentParameter.getName(), currentParameter);
}
} else if ((!checkParamsIncludeExclude(exclude, name))) {
parameters.put(currentParameter.getName(), currentParameter);
}
} else if (methodName.equals("sectionOrder")) {
try {
Method order = null;
order = test.getClass().getMethod("sectionOrder", new Class[0]);
if (order != null) {
if (order.getReturnType().equals(Array.newInstance(String.class, 0).getClass())) {
String[] orderString = (String[]) order.invoke(test, new Object[0]);
setSectionOrder(orderString);
}
}
} catch (Exception e) {
log.log(Level.WARNING, "Fail to get method sectionOrder() from class " + className);
}
}
}
updateInternalJsystemFlags();
updateParamsOrder(include);
}
protected void updateInternalJsystemFlags() {
/**
* All internal JSystem flags and its default values
*/
String[][] keysAndValues = new String[][] { { RunningProperties.HIDDEN_IN_HTML, "false" },
{ RunningProperties.IS_DISABLED, "false" },
{ RunningProperties.MARKED_AS_KNOWN_ISSUE, "false" },
// APPLIED - default value assigned to edit local only
{ RunningProperties.EDIT_ONLY_LOCALLY, "false" },
{ RunningProperties.MARKED_AS_NEGATIVE_TEST, "false" }, { RunningProperties.DOCUMENTATION_TAG, "" },
{ RunningProperties.COMMENT_TAG, "" }, };
for (String[] keyAndValue : keysAndValues) {
Parameter p = new Parameter();
p.setParamClass(String.class);
p.setType(ParameterType.JSYSTEM_INTERNAL_FLAG);
p.setName(keyAndValue[0]);
p.setValue(keyAndValue[1]);
p.setDefaultValue(keyAndValue[1]);
p.setVisible(false);
parameters.put(keyAndValue[0], p);
}
}
private void updateOptions(Class<?> type, Parameter param) {
try {
Method options = null;
options = test.getClass().getMethod("get" + param.getName() + "Options", new Class[0]);
if (options != null) {
if (type == null || options.getReturnType().equals(Array.newInstance(type, 0).getClass())
|| (type.equals(options.getReturnType()) && Object[].class.isAssignableFrom(type))) {
Object optionsArray = options.invoke(test, new Object[0]);
if (optionsArray != null) { // there are values
param.setOptions(optionsArray);
param.setAsOptions(true);
}
}
}
} catch (Throwable throwable) {
// ignored
}
}
protected static boolean checkParamsIncludeExclude(String paramsInclude, String parameter) {
String[] paramsIncludeArray = StringUtils.split(paramsInclude, " ;,\n\r\t");
Set<String> mySet = new HashSet<String>();
for (String s : paramsIncludeArray) {
mySet.add(lowerFirstLetter(s));
}
boolean result = mySet.contains(lowerFirstLetter(parameter));
return result;
}
/**
* tries to set a parameters value located the parameter in the hashmap and
* changes the value.
*/
public void setParameterIfExists(Parameter param) {
Object[] arrayObject = parameters.values().toArray();
for (int i = 0; i < arrayObject.length; i++) {
Parameter currentParameter = (Parameter) arrayObject[i];
if (currentParameter.getName().equals(param.getName()) && (currentParameter.getType() == param.getType())) {
currentParameter.setValue(param.getValue());
return;
}
}
}
/**
* Activates class setters and sets the values of test's members according
* to the <code>parameters</code> map.
*/
@SuppressWarnings("unchecked")
public void setTestClassParameters() {
HashMap<String, Parameter> clone = new HashMap<String, Parameter>(parameters);
Object[] arrayObjects = clone.values().toArray();
for (int i = 0; i < arrayObjects.length; i++) {
Parameter currentParameter = (Parameter) arrayObjects[i];
// skip internal JSystem flags
if (currentParameter.getType().equals(ParameterType.JSYSTEM_INTERNAL_FLAG)) {
continue;
}
Method setter = currentParameter.getSetMethod();
Object ob = currentParameter.getValue();
if (ob == null || currentParameter.isBadRefernceParameter()) {
continue;
}
Class<?>[] types = setter.getParameterTypes();
try {
if (types != null && types.length > 0 && types[0].isEnum()) { // if
// enum
Class type = types[0];
/*
* Convert the string value into Enum
*/
ob = currentParameter.getEnumValueAsName();
setter.invoke(test, new Object[] { Enum.valueOf(type, ob.toString()) });
} else if (types != null && types.length > 0 && File.class.isAssignableFrom(types[0])) { // if
File f = ParameterFileUtils.convertBeforeTestUpdate(ob.toString());
setter.invoke(test, new Object[] { f });
} else if (types != null && types.length > 0 && Date.class.isAssignableFrom(types[0])) { // if
setter.invoke(test, new Object[] { DateUtils.parseDate(ob.toString()) });
} else if (types != null && types.length > 0 && String[].class.isAssignableFrom(types[0])) {// in
// case
// of
// 'string
// array'
if (ob instanceof String) {
ob = StringUtils.split((String) ob, ";");
}
setter.invoke(test, new Object[] { ob });
} else { // not an enum
setter.invoke(test, new Object[] { ob });
}
} catch (Exception e) {
// Fixes issue #232. When parameter from type enum is using a
// value that is longer part of the enum, the value becomes null
// without proper message
ListenerstManager.getInstance().report(
"Failed to set value to parameter with name '" + currentParameter.getName() + "'", 2);
log.log(Level.WARNING, "Failed to set value to parameter with name '" + currentParameter.getName()
+ "'", e);
}
}
}
/**
* Get an array of parameters update the original parameters hash only if
* the parameter exist and changed TODO: same mechanism is correct for
* AntFlowcontrol, so it should be the same code
*/
public void setParameters(Parameter[] params) {
setParameters(params, false);
}
/**
* Get an array of parameters update the original parameters hash only if
* the parameter exist and changed In case that a a parameter value is
* cleared in the Runners GUI, the parameter will be taken out of the
* scenario property file. TODO: same mechanism is correct for
* AntFlowcontrol, so it should be the same code
*/
public void setParameters(Parameter[] params, boolean recursively) {
for (Parameter givenParameter : params) {
if (!givenParameter.isDirty()) {
continue;
}
Parameter originalParameter = parameters.get(givenParameter.getName());
if (originalParameter == null) {
continue;
}
Object value = givenParameter.getValue();
Object value1 = originalParameter.getValue();
if (ObjectUtils.nullSafeEquals(value, value1)) {
continue;
}
boolean isMandatory = givenParameter.isMandatory();
RunnerListenersManager.getInstance().testParametersChanged(getFullUUID(),
new Parameter[] { originalParameter }, new Parameter[] { givenParameter });
originalParameter.setValue(value);
originalParameter.signalToSave();
originalParameter.setMandatory(isMandatory);
String stringValue = originalParameter.getStringValue();
if (stringValue == null) {
properties.remove(originalParameter.getName());
try {
ScenarioHelpers.removePropertiesFromScenarioProps(getRoot().getName(), getFullUUID() + "."
+ givenParameter.getName(), true);
} catch (Exception e) {
log.severe("Problem removing a null parameter from Scenario properties file");
}
} else {
properties.put(originalParameter.getName(), stringValue);
}
}
String originalName = meaningfulName;
if (originalName == null) {
TestProperties tp = getTestProperties();
if (tp != null) {
originalName = StringUtils.isEmpty(tp.name()) ? null : tp.name();
}
}
meaningfulName = processTestName(originalName);
}
private void updateTestInnerFlag(Parameter parameter, String parameterValue) {
parameter.setValue(parameterValue);
properties.put(parameter.getName(), parameterValue);
}
/**
* Sets parameters value according to values which are found in supplied
* properties
*/
private void setParameters() {
if (parameters == null) {
log.warning("Try to load properties when the parameters are not init");
return;
}
Enumeration<Object> enum1 = properties.keys();
while (enum1.hasMoreElements()) {
String key = (String) enum1.nextElement();
Parameter param = (Parameter) parameters.get(key);
if (param != null) {
String value = properties.getProperty(key);
boolean badParameter = value.equals(ParametersManager.BAD_PARAMETER);
param.setBadRefernceParameter(badParameter);
if (badParameter) {
continue;
}
try {
param.setValue(value);
} catch (Exception t) {
ParametersManager.reportExcption(t,
"tried to set value " + value + " to parameter " + param.getName());
}
}
}
}
private HashMap<String, Parameter> getTestParameters() {
if (parameters == null || parameters.size() == 0) {
loadParameters();
}
return parameters;
}
/**
* Returns a <code>Property</code> instance with all test's parameters in
* ant canonical format.
*
* This method is part of the scenario parameterization implementation. When
* running in run.mode 2 or 4, the ant engine is activated with test's
* direct scenario as ant script file and with the test (or several tests
* when running in run.mode 4 ) as the targets. Since test's parameters are
* saved in the parent scenario of the test's scenario (if there is one) ,
* they are lost. To solve this problem, when running in run mode 2,4 tests
* parameters are not passed through the ant file but through a property
* file. This method prepares the properties for the property file.
*
*/
public Properties getPropertiesInAntCanonicalFormat() {
filterProperties(properties);
Properties toReturn = new Properties();
Enumeration<Object> enum1 = properties.keys();
String keyPrefix = getFullTestId() + "/";
while (enum1.hasMoreElements()) {
String key = (String) enum1.nextElement();
toReturn.put(keyPrefix + key, properties.get(key));
}
String key = keyPrefix + RunningProperties.IS_DISABLED;
toReturn.put(key, Boolean.toString(isDisable()));
return toReturn;
}
/**
*/
public Properties getAllXmlFields() {
Properties fields = new Properties();
String com = getComment();
if (com == null) {
com = "";
}
fields.setProperty(commentString, com);
String doc = getDocumentation();
if (doc == null) {
doc = "";
}
fields.setProperty(userDocString, doc);
return fields;
}
/**
* Added to support removal of inner fields that should be removed from test
* properties
*
* @return
*/
public Properties getAllInnerFields() {
Properties base = getAllXmlFields();
base.setProperty(RunningProperties.UUID_PARENT_TAG, "");
base.setProperty(RunningProperties.UUID_TAG, "");
base.setProperty(RunningProperties.IS_DISABLED, "");
base.setProperty(RunningProperties.UI_SETTINGS_TAG, "");
base.setProperty(RunningProperties.HIDDEN_IN_HTML, "");
// APPLIED - Don't know exactly the purpose of this call
base.setProperty(RunningProperties.EDIT_ONLY_LOCALLY, "");
base.setProperty(RunningProperties.DOCUMENTATION_TAG, "");
base.setProperty(RunningProperties.MARKED_AS_KNOWN_ISSUE, "");
base.setProperty(RunningProperties.MARKED_AS_NEGATIVE_TEST, "");
base.setProperty(RunningProperties.COMMENT_TAG, "");
return base;
}
/**
*/
public void setXmlFields(Properties fields) {
setTestComment((String) fields.getProperty(commentString));
setDocumentation((String) fields.getProperty(userDocString));
}
/**
* set this test Test
*
* @param test
* the Test instance
*/
public void setTest(Test test) {
this.test = test;
}
/**
* remove the Test reference sets this Test to null
*/
public void removeTestReferance() {
setTest(null);
}
public String getClassName() {
return className;
}
/**
* set this test class name
*
* @param className
* the string with the class name
*/
public void setClassName(String className) {
this.className = className;
}
/**
* get the test method name
*
* @return method name
*/
public String getMethodName() {
return methodName;
}
/**
* set the method name for this test
*
* @param methodName
* string od the method name
*/
public void setMethodName(String methodName) {
this.methodName = methodName;
}
/**
* get the test properties
*
* @return properties
*/
public Properties getProperties() {
return properties;
}
/**
* set the test properties
*
* @param properties
* properties for the test
*/
public void setProperties(Properties properties) {
this.properties = properties;
}
public Parameter[] getParameters() {
if (parameters == null) {
return new Parameter[0];
}
Parameter[] parameterArray;
if (paramsOrder != null) {
HashMap<String, Parameter> toSort = new HashMap<String, Parameter>(parameters);
ArrayList<Parameter> parameterList = new ArrayList<Parameter>();
parameterArray = new Parameter[toSort.size()];
for (int i = 0; i < paramsOrder.length; i++) {
Parameter currentParameter = toSort.remove(StringUtils.firstCharToUpper(paramsOrder[i]));
if (currentParameter != null) {
parameterList.add(currentParameter);
}
}
for (Parameter currentParameter : toSort.values()) {
parameterList.add(currentParameter);
}
parameterArray = parameterList.toArray(new Parameter[0]);
} else {
parameterArray = parameters.values().toArray(new Parameter[0]);
}
return parameterArray;
}
/**
* get the test's status
*
* @return STAT_NOT_RUN / STAT_RUNNING / STAT_FAIL / STAT_ERROR /
* STAT_SUCCESS / STAT_WARNING
*/
public int getStatus() {
return status;
}
/**
* sets this test status
*
* @param status
* STAT_NOT_RUN / STAT_RUNNING / STAT_FAIL / STAT_ERROR /
* STAT_SUCCESS / STAT_WARNING
*/
public void setStatus(int status) {
if (isMarkedAsKnownIssue() && (status == STAT_ERROR || status == STAT_FAIL)) {
status = STAT_WARNING;
}
this.status = status;
}
public void initFlags() {
if (test instanceof SystemTest) {
((SystemTest) test).initFlags();
}
}
public boolean isDisable() {
if ((parameters == null) || (getTestParameters().get(RunningProperties.IS_DISABLED) == null)) {
return false;
}
return Boolean.parseBoolean(getTestParameters().get(RunningProperties.IS_DISABLED).getStringValue());
}
public void setDisable(boolean isDisable) {
if (isDisable() != isDisable) {
signalToSave(RunningProperties.IS_DISABLED);
}
updateTestInnerFlag(getTestParameters().get(RunningProperties.IS_DISABLED), Boolean.toString(isDisable));
}
public String toString() {
String meaningFul = getMeaningfulName();
if (StringUtils.isEmpty(meaningFul)
|| "true"
.equals(JSystemProperties.getInstance().getPreference(FrameworkOptions.IGNORE_MEANINGFUL_NAME))) {
return StringUtils.getClassName(getClassName()) + "." + getMethodName();
}
return meaningFul;
}
public boolean isError() {
return (status == STAT_ERROR);
}
public boolean isFail() {
return (status == STAT_FAIL);
}
public boolean isRunning() {
return (status == STAT_RUNNING);
}
public boolean isWarning() {
return (status == STAT_WARNING);
}
public boolean isNotRunning() {
return (status == STAT_NOT_RUN);
}
public int countTestCases() {
return 1;
}
public void run(TestResult result) {
test.run(result);
}
public boolean isSuccess() {
return (status == STAT_SUCCESS);
}
/**
* @return True if test was not yet signaled as Fail\Error or Warning
*/
public boolean statusShouldBePass() {
return status != STAT_ERROR && status != STAT_FAIL && status != STAT_WARNING;
}
/**
*
* @return true if the test pass assuming all flags (negative, marked,
* warning etc.), false otherwise
*/
public boolean isPassAssumingFlags() {
// Test status based on test execution without any flags
boolean pass = (status != STAT_ERROR && status != STAT_FAIL);
if (test instanceof SystemTest) {
// Check the SystemTest (actual test) in case a failure/error event
// was not passed on to the RunnerTest.
if (!((SystemTest) test).isPassAccordingToFlags()) {
// Test failed
pass = false;
// Only change the status if the test status was not changed
// already
if (status == STAT_RUNNING) {
setStatus(STAT_FAIL);
}
}
}
if (isMarkedAsNegativeTest()) {
return pass;
}
return pass && status != STAT_WARNING; // for Non-Negative test, warning
// is different from pass
}
/**
* Get the test Java doc
*/
public String getDocumentation() {
if ((parameters == null) || (getTestParameters().get(RunningProperties.DOCUMENTATION_TAG) == null)) {
return "";
}
String doc = getTestParameters().get(RunningProperties.DOCUMENTATION_TAG).getStringValue();
if (StringUtils.isEmpty(doc)) {
setDocumentation(properties.getProperty(userDocString));
return properties.getProperty(userDocString);
}
return doc;
}
public void setDocumentation(String documentation) {
if (StringUtils.isEmpty(getTestParameters().get(RunningProperties.DOCUMENTATION_TAG).getStringValue())
&& (StringUtils.isEmpty(documentation))) {
return;
}
if (((getTestParameters().get(RunningProperties.DOCUMENTATION_TAG).getStringValue() == null && documentation != null))
|| (!(getTestParameters().get(RunningProperties.DOCUMENTATION_TAG).getStringValue()
.equals(documentation)))) {
signalToSave(RunningProperties.DOCUMENTATION_TAG);
}
updateTestInnerFlag(getTestParameters().get(RunningProperties.DOCUMENTATION_TAG), documentation);
}
public void setFixture(String className) throws Exception {
associatedFixtureClassName = className;
}
public String getTestName() {
String comment = getComment();
if (StringUtils.isEmpty(comment)) {
return toString();
}
return toString() + " - " + comment;
}
public void setTestComment(String comment) {
if (StringUtils.isEmpty(getTestParameters().get(RunningProperties.COMMENT_TAG).getStringValue())
&& (StringUtils.isEmpty(comment))) {
return;
}
if (((getTestParameters().get(RunningProperties.COMMENT_TAG).getStringValue() == null && comment != null))
|| (!(getTestParameters().get(RunningProperties.COMMENT_TAG).getStringValue().equals(comment)))) {
signalToSave(RunningProperties.COMMENT_TAG);
}
updateTestInnerFlag(getTestParameters().get(RunningProperties.COMMENT_TAG), comment);
}
public String getComment() {
if ((parameters == null) || (getTestParameters().get(RunningProperties.COMMENT_TAG) == null)) {
return null;
}
return getTestParameters().get(RunningProperties.COMMENT_TAG).getStringValue();
}
/**
* get the section order String array from the test file
*
* @return a string array with the sorting of the sections
*/
public String[] getSectionOrder() {
return sectionOrder;
}
/**
* sets the read from test file section order
*
* @param sectionArray
* the String array of the sorting
*/
public void setSectionOrder(String[] sectionArray) {
this.sectionOrder = sectionArray;
}
/**
*/
private void updateParamsOrder(String paramsInclude) {
if (StringUtils.isEmpty(paramsInclude)) {
return;
}
paramsOrder = StringUtils.split(paramsInclude, ",; \n\r\t");
}
public PresentationDefinitions getPresentationObject() {
return sort;
}
public void setPresentationObject(PresentationDefinitions sort) {
this.sort = sort;
}
public String getTestId() {
return testId;
}
public void setTestId(String testId) {
this.testId = testId;
}
public String getFullTestId() {
return getParent().getFullTestId() + "/" + getTestId();
}
public String getMeaningfulName() {
if (!StringUtils.isEmpty(meaningfulName)) {
return meaningfulName;
}
return codeMeaningfulName;
}
public String[] getGroups() {
return groups;
}
public JTestContainer getParent() {
return parent;
}
public void setParent(JTestContainer parent) {
this.parent = parent;
}
private void filterProperties(Properties props) {
props.remove(RunningProperties.COMMENT_TAG);
props.remove(RunningProperties.DOCUMENTATION_TAG);
props.remove(RunningProperties.IS_DISABLED);
props.remove(RunningProperties.FIXTURE_PROPERTY_NAME);
props.remove(RunningProperties.UUID_PARENT_TAG);
props.remove(RunningProperties.UUID_TAG);
}
public void addPrivateTags(Document doc, Element jsystem) {
// not implemented for RunnerTest (see RunnerScript)
}
public String getUUID() {
if (StringUtils.isEmpty(uuid)) {
throw new IllegalStateException("Test unique id is empty");
}
return uuid;
}
public void setUUID(String UUID) {
this.uuid = UUID;
}
public String getFullUUID() {
if (parent == null) {
return "";
}
String parentFullUuid = parent.getFullUUID();
String fullTmp = StringUtils.isEmpty(parentFullUuid) ? uuid : parentFullUuid + "." + uuid;
return fullTmp;
}
public String getUUIDUpTo(JTest toStopAt) {
if (parent == null) {
return "";
}
String parentFullUuid = parent.getUUIDUpTo(toStopAt);
String fullTmp = StringUtils.isEmpty(parentFullUuid) ? uuid : parentFullUuid + "." + uuid;
return fullTmp;
}
@Override
public DistributedExecutionParameter[] getDistributedExecutionParameters() throws Exception {
return DistributedExecutionHelper.getHostsParameters(this);
}
@Override
public void setDistributedExecutionParameters(DistributedExecutionParameter[] parameters) throws Exception {
DistributedExecutionParameter[] before = getDistributedExecutionParameters();
DistributedExecutionParameter[] after = parameters;
DistributedExecutionHelper.setHostsParameters(this, parameters);
RunnerListenersManager.getInstance().testParametersChanged(getFullUUID(), before, after);
}
public String getIncludeParamsStringAnnotation() {
return includeParamsStringAnnotation;
}
public String getExcludeParamsStringAnnotation() {
return excludeParamsStringAnnotation;
}
@Override
public Scenario getMyScenario() {
return getParent().getMyScenario();
}
@Override
public Scenario getParentScenario() {
return getParent().getParentScenario();
}
@Override
public Scenario getRoot() {
JTest toReturn = this;
while (toReturn.getParent() != null) {
toReturn = toReturn.getParent();
}
return (Scenario) toReturn;
}
@Override
public void update() throws Exception {
getMyScenario().update();
}
public boolean isMarkedAsKnownIssue() {
if ((parameters == null) || (getTestParameters().get(RunningProperties.MARKED_AS_KNOWN_ISSUE) == null)) {
return false;
}
return Boolean.parseBoolean(getTestParameters().get(RunningProperties.MARKED_AS_KNOWN_ISSUE).getStringValue());
}
public boolean isMarkedAsNegativeTest() {
if ((parameters == null) || (getTestParameters().get(RunningProperties.MARKED_AS_NEGATIVE_TEST) == null)) {
return false;
}
return Boolean
.parseBoolean(getTestParameters().get(RunningProperties.MARKED_AS_NEGATIVE_TEST).getStringValue());
}
public void markAsKnownIssue(boolean markedAsKnownIssue) {
if (isMarkedAsKnownIssue() != markedAsKnownIssue) {
signalToSave(RunningProperties.MARKED_AS_KNOWN_ISSUE);
}
updateTestInnerFlag(getTestParameters().get(RunningProperties.MARKED_AS_KNOWN_ISSUE),
Boolean.toString(markedAsKnownIssue));
}
public void markAsNegativeTest(boolean isNegativeTest) {
if (isMarkedAsNegativeTest() != isNegativeTest) {
signalToSave(RunningProperties.MARKED_AS_NEGATIVE_TEST);
}
updateTestInnerFlag(getTestParameters().get(RunningProperties.MARKED_AS_NEGATIVE_TEST),
Boolean.toString(isNegativeTest));
}
public void addValidationError(ValidationError error) {
validationErrors.add(error);
}
public List<ValidationError> getValidationErrors() {
return validationErrors;
}
public boolean isValidationErrorsFound() {
return (validationErrors.size() > 0);
}
public String getValidationErrorsAsString() {
StringBuffer buf = new StringBuffer();
for (ValidationError error : validationErrors) {
buf.append(error.getTitle());
buf.append("\n");
}
return buf.toString();
}
@Override
public void hideInHTML(boolean isHideInHTML) {
if (isHiddenInHTML() != isHideInHTML) {
signalToSave(RunningProperties.HIDDEN_IN_HTML);
}
updateTestInnerFlag(getTestParameters().get(RunningProperties.HIDDEN_IN_HTML), Boolean.toString(isHideInHTML));
}
private void signalToSave(String parameterName) {
getTestParameters().get(parameterName).signalToSave();
}
@Override
public boolean isHiddenInHTML() {
if ((parameters == null) || (getTestParameters().get(RunningProperties.HIDDEN_IN_HTML) == null)) {
return false;
}
return Boolean.parseBoolean(getTestParameters().get(RunningProperties.HIDDEN_IN_HTML).getStringValue());
}
public void setFailureOccurred(boolean failureOccurred) {
this.failureOccurred = failureOccurred;
if (test instanceof SystemTest) {
((SystemTest) test).setPass(false);
}
}
public boolean isFailureOccurred() {
return failureOccurred;
}
public void setMeaningfulName(String meaningfulName, boolean saveToPropFile) {
meaningfulNameShouldBeSaved = saveToPropFile;
if (StringUtils.isEmpty(meaningfulName)) {
loadMeaningfulName(false);
} else {
this.meaningfulName = meaningfulName;
}
}
/**
* Delete the properties of the test from the property file of the current
* root scenario
*/
// Limor Bortman
@Override
public void resetToDefault() throws Exception {
Scenario root = getRoot();
root.save();
String id = getUUIDUpTo(root);
ScenarioHelpers.removePropertiesFromScenarioProps(root.getName(), id, false);
root.load();
}
}