1 /* 2 * Copyright (c) 2009, 2012, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 */ 24 25 package client.test.runner; 26 27 import java.io.File; 28 import java.io.IOException; 29 import java.io.ObjectInputStream; 30 import java.io.ObjectOutputStream; 31 import java.io.PrintStream; 32 import java.io.Serializable; 33 import java.net.Socket; 34 import java.util.concurrent.Semaphore; 35 import org.junit.runner.JUnitCore; 36 import org.junit.runner.Request; 37 import org.junit.runner.Result; 38 import org.junit.runner.notification.Failure; 39 import org.junit.runner.notification.RunListener; 40 import test.javaclient.shared.screenshots.ImagesManager; 41 42 /** 43 * 44 * @author shura, mrkam, Sergey Grinev, Victor Shubov 45 */ 46 public class CommonTestRunnerWorker { 47 48 static final int DEFAULT_PORT = 56179; 49 50 private final JUnitCore core = new JUnitCore(); 51 private Abstract2TestRunner testRunner; 52 private final Semaphore uilock = new Semaphore(0); 53 private Socket socket; 54 private String testClassName; 55 private String testName; 56 private long testStart; 57 private String host = "127.0.0.1"; 58 private boolean debugMode = false; 59 private volatile boolean isExiting = false; 60 61 private CommonTestRunnerWorker() { 62 } 63 64 /** 65 * 66 * @param _testRunner 67 */ 68 public CommonTestRunnerWorker(Abstract2TestRunner _testRunner) { 69 testRunner = _testRunner; 70 } 71 72 private final Thread exitThread = new Thread(new Runnable() { 73 @Override 74 public void run() { 75 waitUI(); 76 exit(testRunner.getCurrentStatus()); 77 } 78 }, "exit waiter"); 79 80 static int getTestPort() { 81 return Integer.valueOf(System.getProperty("masterPort", String.valueOf(DEFAULT_PORT))); 82 } 83 /** 84 * 85 * @throws Throwable 86 */ 87 public void runUI() throws Throwable { 88 System.out.println("CommonTestRunnerWorker.runUI(): starting test..."); 89 core.addListener(new RunListener() { 90 91 @Override 92 public void testAssumptionFailure(Failure failure) { 93 System.out.println("junit failure: " + failure.getMessage()); 94 failure.getException().printStackTrace(); 95 exit(Abstract2TestRunner.Status.FAIL); 96 } 97 98 @Override 99 public void testFailure(Failure failure) throws Exception { 100 System.out.println("junit failure: " + failure.getMessage()); 101 failure.getException().printStackTrace(); 102 exit(Abstract2TestRunner.Status.FAIL); 103 } 104 105 }); 106 Result r = core.run(Request.method(Class.forName(testClassName), testName)); 107 System.out.println("got result = " + r.wasSuccessful()); 108 exit(r.wasSuccessful() ? Abstract2TestRunner.Status.PASS : Abstract2TestRunner.Status.FAIL); 109 } 110 111 private void waitUI() { 112 if (!uilock.tryAcquire()) { 113 report("Waiting for UI to start or nodesc/auto test to finish"); 114 try { 115 uilock.acquire(); 116 } catch (InterruptedException ignored) { 117 ignored.printStackTrace(); 118 } 119 } 120 report("UI started successfully"); 121 } 122 123 /** 124 * 125 * @param text 126 */ 127 protected void report(String text) { 128 long time = System.nanoTime() - testStart; 129 System.out.printf("%dms: %s\n", time / 1000000, text); 130 } 131 132 private void handleEx(Throwable ex) { 133 ex.printStackTrace(); 134 exit(Abstract2TestRunner.Status.ERROR); 135 } 136 137 /** 138 * 139 * @param args 140 */ 141 protected final void setArgs(final String... args) { 142 if (args != null && args.length > 0) { 143 if (args.length == 1) { 144 testClassName = args[0]; 145 } else if (args.length >= 3 && args[0].equals("--debug")) { 146 System.err.println("debug mode"); 147 debugMode = true; 148 testClassName = args[1]; 149 testName = args[2]; 150 } else { 151 System.err.println("remote mode"); 152 testClassName = args[0]; 153 host = args[1]; 154 } 155 } 156 if (null == testClassName) { 157 System.err.println("null == testClassName, argslen=" + args.length); 158 } 159 } 160 161 /** 162 * 163 * @return 164 */ 165 public String getTestClassName() { 166 return testClassName; 167 } 168 169 /** 170 * 171 * @return 172 */ 173 public String getTestName() { 174 return testName; 175 } 176 177 /** 178 * 179 */ 180 protected final void prepareAndRunTest() { 181 182 if (debugMode) { 183 runTest(); 184 System.err.println("Test done."); 185 return; 186 } 187 188 testStart = System.nanoTime(); 189 try { 190 int port = getTestPort(); 191 report("Looking for server at host " + host + ", port " + port + "..."); 192 socket = new Socket(host, port); 193 ObjectInputStream readerStream = new ObjectInputStream(socket.getInputStream()); 194 report("Connected"); 195 196 loop: 197 do { 198 Command trc = (Command) readerStream.readObject(); 199 report("Got command: " + trc.type + ":" + trc.param); 200 switch (trc.type) { 201 case SET_TEST_CLASS: 202 testClassName = trc.param; 203 break; 204 case SET_BASEDIR: 205 //TODO: this design is a bit flawed as we introducing backward 206 //dependency on SharedTestUtils here. 207 ImagesManager.getInstance().setBaseDir(trc.param); 208 break; 209 case SET_ABSOLUTE_DIR: 210 ImagesManager.getInstance().setAbsoluteDir(trc.param); 211 break; 212 case SET_TEST_NAME: 213 testName = trc.param; 214 break; 215 case SET_ERR: 216 System.setErr(new PrintStream(new File(trc.param))); 217 break; 218 case SET_OUT: 219 System.setOut(new PrintStream(new File(trc.param))); 220 break; 221 case RUN_TEST: 222 if (testClassName == null) { 223 handleEx(new IllegalStateException("Running test without classname!")); 224 break loop; 225 } else { 226 runTest(); 227 } 228 break; 229 case CHECK_UI_AND_EXIT: 230 try { 231 waitUI(); 232 testRunner.checkUI(); 233 } catch (Throwable ex) { 234 handleEx(ex); 235 } 236 exit(testRunner.getCurrentStatus()); 237 break; 238 case EXIT: 239 // we want be able to wait for abort here 240 if (!exitThread.isAlive()) { 241 exitThread.start(); 242 } 243 break; 244 case ABORT: 245 exit(Abstract2TestRunner.Status.ABORTED); 246 break; 247 default: 248 exit(Abstract2TestRunner.Status.UKNOWN_COMMAND); 249 break; 250 } 251 252 } while (true); 253 readerStream.close(); 254 } catch (Throwable ex) { 255 if (!isExiting) { 256 handleEx(ex); 257 } 258 } 259 } 260 261 private void runTest() { 262 testStart = System.nanoTime(); 263 new Thread(new Runnable() { 264 @Override 265 public void run() { 266 report("CommonTestRunnerWorker.runTest(): starting UI ..."); 267 try { 268 testRunner.runUI(); 269 } catch (Throwable ex) { 270 handleEx(ex); 271 } finally { 272 report("UI started"); 273 uilock.release(1000); 274 } 275 } 276 }).start(); 277 } 278 279 /** 280 * 281 * @param exitStatus 282 */ 283 protected synchronized void exit(Abstract2TestRunner.Status exitStatus) { 284 Abstract2TestRunner.Status exitValue = exitStatus; 285 System.err.println("called exit " + exitValue); 286 287 try { 288 System.err.println("call stopui"); 289 testRunner.stopUI(); 290 } catch (Throwable ex) { 291 ex.printStackTrace(); 292 exitValue = Abstract2TestRunner.Status.ERROR; 293 } 294 295 report("Exiting with status: " + exitValue); 296 isExiting = true; 297 if (socket != null && socket.isConnected()) { 298 try { 299 new ObjectOutputStream(socket.getOutputStream()).writeObject(exitValue); 300 } catch (IOException ex) { 301 ex.printStackTrace(); 302 } 303 } 304 System.exit(exitValue.getN()); 305 } 306 307 static class Command implements Serializable { 308 static enum CommandType { 309 CHECK_UI_AND_EXIT, 310 ABORT, 311 STOP_UI, 312 EXIT, 313 SET_TEST_CLASS, 314 SET_TEST_NAME, 315 SET_ERR, 316 SET_OUT, 317 //SET_SUITE_NAME, 318 SET_BASEDIR, 319 SET_ABSOLUTE_DIR, 320 RUN_TEST; 321 } 322 final String param; 323 final CommandType type; 324 325 @Override 326 public String toString() { 327 return "TestRunnerCommand{type='" + type + "',param='" + param + "'}"; 328 } 329 330 public Command(CommandType cmd, String param) { 331 this.param = param; 332 this.type = cmd; 333 } 334 } 335 336 }