Test.java revision 13978:1993af50385d
1/* 2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23package org.netbeans.jemmy; 24 25import java.io.PrintStream; 26import java.io.PrintWriter; 27import java.lang.reflect.InvocationTargetException; 28 29/** 30 * 31 * Jemmy itself provides a way to create tests. Test should implement 32 * org.netbeans.jemmy.Scenario interface. 33 * 34 * Test can be executed from command line:<BR> 35 * {@code java [application options] [jemmy options] org.netbeans.jemmy.Test [full name of test class] [test args]}<BR> 36 * Test elso can be executed by one of the run(...) methods or by <BR> 37 * {@code new Test([test class name]).startTest([test args]);}<BR> 38 * 39 * <BR><BR>Timeouts used: <BR> 40 * Test.WholeTestTimeout - time for the whole test<BR> 41 * 42 * @author Alexandre Iline (alexandre.iline@oracle.com) 43 */ 44public class Test extends ActionProducer<Object, Object> 45 implements Timeoutable, Outputable, Scenario { 46 47 private final static long WHOLE_TEST_TIMEOUT = 3600000; 48 49 /** 50 * Status returned by test if wrong parameter was passed. 51 */ 52 public static int WRONG_PARAMETERS_STATUS = 101; 53 54 /** 55 * Status returned by test if exception appeared inside scenario. 56 */ 57 public static int SCENARIO_EXCEPTION_STATUS = 102; 58 59 /** 60 * Positive test status. 61 */ 62 public static int TEST_PASSED_STATUS = 0; 63 64 /** 65 * Test timeouts. 66 */ 67 protected Timeouts timeouts; 68 69 /** 70 * Test output. 71 */ 72 protected TestOut output; 73 74 private Scenario scenario; 75 76 /** 77 * Constructor for tests requiring only a class instance. Creates a subclass 78 * of {@code ActionProducer} and {@code java.lang.Thread} that 79 * runs in a separate thread of execution and waits for execution to finish. 80 * The current output stream assignments and timeouts are used. 81 * 82 * @param testClassName Full test class name 83 */ 84 public Test(String testClassName) { 85 super(true); 86 setOutput(JemmyProperties.getCurrentOutput()); 87 setTimeouts(JemmyProperties.getCurrentTimeouts()); 88 scenario = testForName(testClassName); 89 } 90 91 /** 92 * Constructor for scenarios that require an instance and might require an 93 * argument. Creates a subclass of {@code ActionProducer} and 94 * {@code java.lang.Thread} that runs in a separate thread of execution 95 * and waits for execution to finish. The current output stream assignments 96 * and timeouts are used. 97 * 98 * @param scenario a test scenario 99 * @see org.netbeans.jemmy.Scenario 100 */ 101 public Test(Scenario scenario) { 102 super(true); 103 setOutput(JemmyProperties.getCurrentOutput()); 104 setTimeouts(JemmyProperties.getCurrentTimeouts()); 105 this.scenario = scenario; 106 } 107 108 /** 109 * No argument constructor. Used by subclasses of this {@code Test} 110 * class. Creates a subclass of {@code ActionProducer} and 111 * {@code java.lang.Thread} that runs in a separate thread of execution 112 * and waits for execution to finish. The current output stream assignments 113 * and timeouts are used. 114 */ 115 protected Test() { 116 super(true); 117 setOutput(JemmyProperties.getCurrentOutput()); 118 setTimeouts(JemmyProperties.getCurrentTimeouts()); 119 } 120 121 /** 122 * Throws TestCompletedException exception. The exception thrown contains a 123 * pass/fail status and a short status {@code java.lang.String}. Can by 124 * invoked from test to abort test execution. 125 * 126 * @param status If 0 - test passed, otherwise failed. 127 * @throws TestCompletedException all of the time. 128 */ 129 public static void closeDown(int status) { 130 if (status == 0) { 131 throw (new TestCompletedException(status, "Test passed")); 132 } else { 133 throw (new TestCompletedException(status, "Test failed with status " 134 + Integer.toString(status))); 135 } 136 } 137 138 /** 139 * Executes a test. 140 * 141 * @param argv First element should be a test class name, all others - test 142 * args. 143 * @return test status. 144 */ 145 public static int run(String[] argv) { 146 String[] args = argv; 147 JemmyProperties.getProperties().init(); 148 if (argv.length < 1) { 149 JemmyProperties.getCurrentOutput(). 150 printErrLine("First element of String array should be test classname"); 151 return WRONG_PARAMETERS_STATUS; 152 } 153 JemmyProperties.getCurrentOutput().printLine("Executed test " + argv[0]); 154 Test test = new Test(argv[0]); 155 if (argv.length >= 1) { 156 args = shiftArray(args); 157 } 158 if (argv.length >= 2) { 159 JemmyProperties.getCurrentOutput().printLine("Work directory: " + argv[1]); 160 System.setProperty("user.dir", argv[1]); 161 args = shiftArray(args); 162 } 163 int status; 164 status = test.startTest(args); 165 JemmyProperties.getCurrentOutput().flush(); 166 return status; 167 } 168 169 /** 170 * Executes a test. 171 * 172 * @param argv First element should be a test class name, all others - test 173 * args. 174 * @param output Stream to put test output and errput into. 175 * @return test status. 176 */ 177 public static int run(String[] argv, PrintStream output) { 178 JemmyProperties.setCurrentOutput(new TestOut(System.in, output, output)); 179 return run(argv); 180 } 181 182 /** 183 * Executes a test. 184 * 185 * @param argv First element should be a test class name, all others - test 186 * args. 187 * @param output Stream to put test output into. 188 * @param errput Stream to put test errput into. 189 * @return test status. 190 */ 191 public static int run(String[] argv, PrintStream output, PrintStream errput) { 192 JemmyProperties.setCurrentOutput(new TestOut(System.in, output, errput)); 193 return run(argv); 194 } 195 196 /** 197 * Executes a test. 198 * 199 * @param argv First element should be a test class name, all others - test 200 * args. 201 * @param output Writer to put test output and errput into. 202 * @return test status. 203 */ 204 public static int run(String[] argv, PrintWriter output) { 205 JemmyProperties.setCurrentOutput(new TestOut(System.in, output, output)); 206 return run(argv); 207 } 208 209 /** 210 * Executes a test. 211 * 212 * @param argv First element should be a test class name, all others - test 213 * args. 214 * @param output Writer to put test output into. 215 * @param errput Writer to put test errput into. 216 * @return test status. 217 */ 218 public static int run(String[] argv, PrintWriter output, PrintWriter errput) { 219 JemmyProperties.setCurrentOutput(new TestOut(System.in, output, errput)); 220 return run(argv); 221 } 222 223 /** 224 * Invoke this {@code Test}. The call might be directly from the 225 * command line. 226 * 227 * @param argv First element should be a test class name, all others - test 228 * args. 229 */ 230 public static void main(String[] argv) { 231 System.exit(run(argv, System.out)); 232 } 233 234 static { 235 Timeouts.initDefault("Test.WholeTestTimeout", WHOLE_TEST_TIMEOUT); 236 } 237 238 /** 239 * Creates an instance of a class named by the parameter. 240 * 241 * @param testName Full test class name 242 * @return an instance of the test {@code Scenario} to launch. 243 * @see org.netbeans.jemmy.Scenario 244 */ 245 public Scenario testForName(String testName) { 246 try { 247 return ((Scenario) (Class.forName(testName). 248 getConstructor(new Class<?>[0]). 249 newInstance())); 250 } catch (ClassNotFoundException e) { 251 output.printErrLine("Class " + testName + " does not exist!"); 252 output.printStackTrace(e); 253 } catch (NoSuchMethodException e) { 254 output.printErrLine("Class " + testName + " has not constructor!"); 255 output.printStackTrace(e); 256 } catch (InvocationTargetException e) { 257 output.printErrLine("Exception inside " + testName + " constructor:"); 258 output.printStackTrace(e.getTargetException()); 259 } catch (IllegalAccessException e) { 260 output.printErrLine("Cannot access to " + testName + " constructor!"); 261 output.printStackTrace(e); 262 } catch (InstantiationException e) { 263 output.printErrLine("Cannot instantiate " + testName + " class!"); 264 output.printStackTrace(e); 265 } 266 return null; 267 } 268 269 /** 270 * Set the timeouts used by this {@code Test}. 271 * 272 * @param timeouts A collection of timeout assignments. 273 * @see org.netbeans.jemmy.Timeoutable 274 * @see org.netbeans.jemmy.Timeouts 275 * @see #getTimeouts 276 */ 277 @Override 278 public void setTimeouts(Timeouts timeouts) { 279 this.timeouts = timeouts; 280 Timeouts times = timeouts.cloneThis(); 281 times.setTimeout("ActionProducer.MaxActionTime", 282 timeouts.getTimeout("Test.WholeTestTimeout")); 283 super.setTimeouts(times); 284 } 285 286 /** 287 * Get the timeouts used by this {@code Test}. 288 * 289 * @see org.netbeans.jemmy.Timeoutable 290 * @see org.netbeans.jemmy.Timeouts 291 * @see #setTimeouts 292 */ 293 @Override 294 public Timeouts getTimeouts() { 295 return timeouts; 296 } 297 298 /** 299 * Set the streams or writers used for print output. 300 * 301 * @param out An object used to identify both output and error print 302 * streams. 303 * @see org.netbeans.jemmy.Outputable 304 * @see org.netbeans.jemmy.TestOut 305 * @see #getOutput 306 */ 307 @Override 308 public void setOutput(TestOut out) { 309 output = out; 310 super.setOutput(out); 311 } 312 313 /** 314 * Get the streams or writers used for print output. 315 * 316 * @return an object containing references to both output and error print 317 * streams. 318 * @see org.netbeans.jemmy.Outputable 319 * @see org.netbeans.jemmy.TestOut 320 * @see #setOutput 321 */ 322 @Override 323 public TestOut getOutput() { 324 return output; 325 } 326 327 /** 328 * Executes test. 329 * 330 * @param param Object to be passed into this test's launch(Object) method. 331 * @return test status. 332 */ 333 public int startTest(Object param) { 334 if (scenario != null) { 335 output.printLine("Test " + scenario.getClass().getName() 336 + " has been started"); 337 } else { 338 output.printLine("Test " + getClass().getName() 339 + " has been started"); 340 } 341 try { 342 return ((Integer) produceAction(param, "Test.WholeTestTimeout")).intValue(); 343 } catch (InterruptedException e) { 344 output.printErrLine("Test was interrupted."); 345 output.printStackTrace(e); 346 } catch (TimeoutExpiredException e) { 347 output.printErrLine("Test was not finished in " 348 + Long.toString(timeouts.getTimeout("Test.WholeTestTimeout")) 349 + " milliseconds"); 350 output.printStackTrace(e); 351 } catch (Exception e) { 352 output.printStackTrace(e); 353 } 354 return 1; 355 } 356 357 /** 358 * Launch an action. Pass arguments to and execute a test 359 * {@code Scenario}. 360 * 361 * @param obj An argument object that controls test execution. This might be 362 * a {@code java.lang.String[]} containing command line arguments. 363 * @see org.netbeans.jemmy.Action 364 * @return an Integer containing test status. 365 */ 366 @Override 367 public final Object launch(Object obj) { 368 setTimeouts(timeouts); 369 try { 370 if (scenario != null) { 371 closeDown(scenario.runIt(obj)); 372 } else { 373 closeDown(runIt(obj)); 374 } 375 } catch (TestCompletedException e) { 376 output.printStackTrace(e); 377 return e.getStatus(); 378 } catch (Throwable e) { 379 output.printStackTrace(e); 380 return SCENARIO_EXCEPTION_STATUS; 381 } 382 return TEST_PASSED_STATUS; 383 } 384 385 /** 386 * Supposed to be overridden to print a synopsys into test output. 387 */ 388 public void printSynopsis() { 389 output.printLine("Here should be a test synopsis."); 390 } 391 392 /** 393 * @see org.netbeans.jemmy.Action 394 */ 395 @Override 396 public final String getDescription() { 397 return "Test " + scenario.getClass().getName() + " finished"; 398 } 399 400 @Override 401 public String toString() { 402 return "Test{" + "scenario=" + scenario + '}'; 403 } 404 405 /** 406 * Defines a way to execute this {@code Test}. 407 * 408 * @param param An object passed to configure the test scenario execution. 409 * For example, this parameter might be a <code>java.lang.String[]<code> object that lists the 410 * command line arguments to the Java application corresponding 411 * to a test. 412 * @return an int that tells something about the execution. For, example, a 413 * status code. 414 * @see org.netbeans.jemmy.Scenario 415 */ 416 @Override 417 public int runIt(Object param) { 418 return 0; 419 } 420 421 /** 422 * Sleeps. 423 * 424 * @param time The sleep time in milliseconds. 425 */ 426 protected void doSleep(long time) { 427 try { 428 Thread.sleep(time); 429 } catch (InterruptedException e) { 430 } 431 } 432 433 private static String[] shiftArray(String[] orig) { 434 String[] result = new String[orig.length - 1]; 435 for (int i = 0; i < result.length; i++) { 436 result[i] = orig[i + 1]; 437 } 438 return result; 439 } 440 441} 442