blob: c1aa27810046c959f5c21f1670b553afb6b2a028 [file] [log] [blame]
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.netbeans.jemmy;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
/**
*
* Jemmy itself provides a way to create tests. Test should implement
* org.netbeans.jemmy.Scenario interface.
*
* Test can be executed from command line:<BR>
* {@code java [application options] [jemmy options] org.netbeans.jemmy.Test [full name of test class] [test args]}<BR>
* Test elso can be executed by one of the run(...) methods or by <BR>
* {@code new Test([test class name]).startTest([test args]);}<BR>
*
* <BR><BR>Timeouts used: <BR>
* Test.WholeTestTimeout - time for the whole test<BR>
*
* @author Alexandre Iline (alexandre.iline@oracle.com)
*/
public class Test extends ActionProducer<Object, Object>
implements Timeoutable, Outputable, Scenario {
private final static long WHOLE_TEST_TIMEOUT = 3600000;
/**
* Status returned by test if wrong parameter was passed.
*/
public static int WRONG_PARAMETERS_STATUS = 101;
/**
* Status returned by test if exception appeared inside scenario.
*/
public static int SCENARIO_EXCEPTION_STATUS = 102;
/**
* Positive test status.
*/
public static int TEST_PASSED_STATUS = 0;
/**
* Test timeouts.
*/
protected Timeouts timeouts;
/**
* Test output.
*/
protected TestOut output;
private Scenario scenario;
/**
* Constructor for tests requiring only a class instance. Creates a subclass
* of {@code ActionProducer} and {@code java.lang.Thread} that
* runs in a separate thread of execution and waits for execution to finish.
* The current output stream assignments and timeouts are used.
*
* @param testClassName Full test class name
*/
public Test(String testClassName) {
super(true);
setOutput(JemmyProperties.getCurrentOutput());
setTimeouts(JemmyProperties.getCurrentTimeouts());
scenario = testForName(testClassName);
}
/**
* Constructor for scenarios that require an instance and might require an
* argument. Creates a subclass of {@code ActionProducer} and
* {@code java.lang.Thread} that runs in a separate thread of execution
* and waits for execution to finish. The current output stream assignments
* and timeouts are used.
*
* @param scenario a test scenario
* @see org.netbeans.jemmy.Scenario
*/
public Test(Scenario scenario) {
super(true);
setOutput(JemmyProperties.getCurrentOutput());
setTimeouts(JemmyProperties.getCurrentTimeouts());
this.scenario = scenario;
}
/**
* No argument constructor. Used by subclasses of this {@code Test}
* class. Creates a subclass of {@code ActionProducer} and
* {@code java.lang.Thread} that runs in a separate thread of execution
* and waits for execution to finish. The current output stream assignments
* and timeouts are used.
*/
protected Test() {
super(true);
setOutput(JemmyProperties.getCurrentOutput());
setTimeouts(JemmyProperties.getCurrentTimeouts());
}
/**
* Throws TestCompletedException exception. The exception thrown contains a
* pass/fail status and a short status {@code java.lang.String}. Can by
* invoked from test to abort test execution.
*
* @param status If 0 - test passed, otherwise failed.
* @throws TestCompletedException all of the time.
*/
public static void closeDown(int status) {
if (status == 0) {
throw (new TestCompletedException(status, "Test passed"));
} else {
throw (new TestCompletedException(status, "Test failed with status "
+ Integer.toString(status)));
}
}
/**
* Executes a test.
*
* @param argv First element should be a test class name, all others - test
* args.
* @return test status.
*/
public static int run(String[] argv) {
String[] args = argv;
JemmyProperties.getProperties().init();
if (argv.length < 1) {
JemmyProperties.getCurrentOutput().
printErrLine("First element of String array should be test classname");
return WRONG_PARAMETERS_STATUS;
}
JemmyProperties.getCurrentOutput().printLine("Executed test " + argv[0]);
Test test = new Test(argv[0]);
if (argv.length >= 1) {
args = shiftArray(args);
}
if (argv.length >= 2) {
JemmyProperties.getCurrentOutput().printLine("Work directory: " + argv[1]);
System.setProperty("user.dir", argv[1]);
args = shiftArray(args);
}
int status;
status = test.startTest(args);
JemmyProperties.getCurrentOutput().flush();
return status;
}
/**
* Executes a test.
*
* @param argv First element should be a test class name, all others - test
* args.
* @param output Stream to put test output and errput into.
* @return test status.
*/
public static int run(String[] argv, PrintStream output) {
JemmyProperties.setCurrentOutput(new TestOut(System.in, output, output));
return run(argv);
}
/**
* Executes a test.
*
* @param argv First element should be a test class name, all others - test
* args.
* @param output Stream to put test output into.
* @param errput Stream to put test errput into.
* @return test status.
*/
public static int run(String[] argv, PrintStream output, PrintStream errput) {
JemmyProperties.setCurrentOutput(new TestOut(System.in, output, errput));
return run(argv);
}
/**
* Executes a test.
*
* @param argv First element should be a test class name, all others - test
* args.
* @param output Writer to put test output and errput into.
* @return test status.
*/
public static int run(String[] argv, PrintWriter output) {
JemmyProperties.setCurrentOutput(new TestOut(System.in, output, output));
return run(argv);
}
/**
* Executes a test.
*
* @param argv First element should be a test class name, all others - test
* args.
* @param output Writer to put test output into.
* @param errput Writer to put test errput into.
* @return test status.
*/
public static int run(String[] argv, PrintWriter output, PrintWriter errput) {
JemmyProperties.setCurrentOutput(new TestOut(System.in, output, errput));
return run(argv);
}
/**
* Invoke this {@code Test}. The call might be directly from the
* command line.
*
* @param argv First element should be a test class name, all others - test
* args.
*/
public static void main(String[] argv) {
System.exit(run(argv, System.out));
}
static {
Timeouts.initDefault("Test.WholeTestTimeout", WHOLE_TEST_TIMEOUT);
}
/**
* Creates an instance of a class named by the parameter.
*
* @param testName Full test class name
* @return an instance of the test {@code Scenario} to launch.
* @see org.netbeans.jemmy.Scenario
*/
public Scenario testForName(String testName) {
try {
return ((Scenario) (Class.forName(testName).
getConstructor(new Class<?>[0]).
newInstance()));
} catch (ClassNotFoundException e) {
output.printErrLine("Class " + testName + " does not exist!");
output.printStackTrace(e);
} catch (NoSuchMethodException e) {
output.printErrLine("Class " + testName + " has not constructor!");
output.printStackTrace(e);
} catch (InvocationTargetException e) {
output.printErrLine("Exception inside " + testName + " constructor:");
output.printStackTrace(e.getTargetException());
} catch (IllegalAccessException e) {
output.printErrLine("Cannot access to " + testName + " constructor!");
output.printStackTrace(e);
} catch (InstantiationException e) {
output.printErrLine("Cannot instantiate " + testName + " class!");
output.printStackTrace(e);
}
return null;
}
/**
* Set the timeouts used by this {@code Test}.
*
* @param timeouts A collection of timeout assignments.
* @see org.netbeans.jemmy.Timeoutable
* @see org.netbeans.jemmy.Timeouts
* @see #getTimeouts
*/
@Override
public void setTimeouts(Timeouts timeouts) {
this.timeouts = timeouts;
Timeouts times = timeouts.cloneThis();
times.setTimeout("ActionProducer.MaxActionTime",
timeouts.getTimeout("Test.WholeTestTimeout"));
super.setTimeouts(times);
}
/**
* Get the timeouts used by this {@code Test}.
*
* @see org.netbeans.jemmy.Timeoutable
* @see org.netbeans.jemmy.Timeouts
* @see #setTimeouts
*/
@Override
public Timeouts getTimeouts() {
return timeouts;
}
/**
* Set the streams or writers used for print output.
*
* @param out An object used to identify both output and error print
* streams.
* @see org.netbeans.jemmy.Outputable
* @see org.netbeans.jemmy.TestOut
* @see #getOutput
*/
@Override
public void setOutput(TestOut out) {
output = out;
super.setOutput(out);
}
/**
* Get the streams or writers used for print output.
*
* @return an object containing references to both output and error print
* streams.
* @see org.netbeans.jemmy.Outputable
* @see org.netbeans.jemmy.TestOut
* @see #setOutput
*/
@Override
public TestOut getOutput() {
return output;
}
/**
* Executes test.
*
* @param param Object to be passed into this test's launch(Object) method.
* @return test status.
*/
public int startTest(Object param) {
if (scenario != null) {
output.printLine("Test " + scenario.getClass().getName()
+ " has been started");
} else {
output.printLine("Test " + getClass().getName()
+ " has been started");
}
try {
return ((Integer) produceAction(param, "Test.WholeTestTimeout")).intValue();
} catch (InterruptedException e) {
output.printErrLine("Test was interrupted.");
output.printStackTrace(e);
} catch (TimeoutExpiredException e) {
output.printErrLine("Test was not finished in "
+ Long.toString(timeouts.getTimeout("Test.WholeTestTimeout"))
+ " milliseconds");
output.printStackTrace(e);
} catch (Exception e) {
output.printStackTrace(e);
}
return 1;
}
/**
* Launch an action. Pass arguments to and execute a test
* {@code Scenario}.
*
* @param obj An argument object that controls test execution. This might be
* a {@code java.lang.String[]} containing command line arguments.
* @see org.netbeans.jemmy.Action
* @return an Integer containing test status.
*/
@Override
public final Object launch(Object obj) {
setTimeouts(timeouts);
try {
if (scenario != null) {
closeDown(scenario.runIt(obj));
} else {
closeDown(runIt(obj));
}
} catch (TestCompletedException e) {
output.printStackTrace(e);
return e.getStatus();
} catch (Throwable e) {
output.printStackTrace(e);
return SCENARIO_EXCEPTION_STATUS;
}
return TEST_PASSED_STATUS;
}
/**
* Supposed to be overridden to print a synopsys into test output.
*/
public void printSynopsis() {
output.printLine("Here should be a test synopsis.");
}
/**
* @see org.netbeans.jemmy.Action
*/
@Override
public final String getDescription() {
return "Test " + scenario.getClass().getName() + " finished";
}
@Override
public String toString() {
return "Test{" + "scenario=" + scenario + '}';
}
/**
* Defines a way to execute this {@code Test}.
*
* @param param An object passed to configure the test scenario execution.
* For example, this parameter might be a <code>java.lang.String[]<code> object that lists the
* command line arguments to the Java application corresponding
* to a test.
* @return an int that tells something about the execution. For, example, a
* status code.
* @see org.netbeans.jemmy.Scenario
*/
@Override
public int runIt(Object param) {
return 0;
}
/**
* Sleeps.
*
* @param time The sleep time in milliseconds.
*/
protected void doSleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
}
}
private static String[] shiftArray(String[] orig) {
String[] result = new String[orig.length - 1];
for (int i = 0; i < result.length; i++) {
result[i] = orig[i + 1];
}
return result;
}
}