1 /* 2 * Copyright (c) 2009, 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. 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 client.test.ExcludeRunModeMethod; 28 import client.test.ExcludeRunModeType; 29 import client.test.OnlyRunModeMethod; 30 import client.test.OnlyRunModeType; 31 import client.test.RunModes; 32 import client.test.RunModes.RunModeException; 33 import client.test.runner.CommonTestRunnerWorker.Command; 34 import client.test.runner.CommonTestRunnerWorker.Command.CommandType; 35 import client.test.runner.interview.LookAndFeelQuestion; 36 import client.test.runner.interview.PipelineQuestion; 37 import client.util.CtrUtils; 38 import static client.util.CtrUtils.*; 39 import client.util.CtrUtils.OutputReader; 40 import client.util.JettyServer; 41 import com.sun.interview.YesNoQuestion; 42 import com.sun.javatest.Status; 43 import com.sun.javatest.TestDescription; 44 import com.sun.javatest.TestEnvironment; 45 import com.sun.javatest.TestEnvironment.Fault; 46 import java.io.*; 47 import java.lang.reflect.Method; 48 import java.net.ServerSocket; 49 import java.net.Socket; 50 import java.net.URL; 51 import java.net.UnknownHostException; 52 import java.util.ArrayList; 53 import java.util.HashSet; 54 import java.util.List; 55 import java.util.Set; 56 import java.util.concurrent.Semaphore; 57 import java.util.concurrent.TimeUnit; 58 import java.util.logging.Level; 59 import java.util.logging.Logger; 60 import org.junit.runner.RunWith; 61 import test.javaclient.shared.CanvasRunner; 62 import test.javaclient.shared.Utils; 63 64 /** 65 * 66 * @author shura, mrkam, Sergey Grinev, Victor Shubov 67 */ 68 public class TestScript extends htmltestrunner.TestScript { 69 70 private static final int FORCED_TERMINATION_TIMEOUT = 5000; 71 private static final boolean verbose = true; //TODO: use real logger 72 private volatile Process process = null; 73 private volatile ServerSocket cmdServer = null; 74 private volatile Socket cmdSocket; 75 private volatile ObjectOutputStream commandStream; 76 private volatile TestRunner.Status status = null; 77 private volatile TestEnvironment savedEnv; 78 private Thread resultThread; 79 80 @Override 81 protected synchronized void interrupt(Status status) { 82 System.out.println("interrupting with status " + status); 83 try { 84 if (process.isAlive()) { 85 process.destroyForcibly().waitFor(FORCED_TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS); 86 } 87 } catch (InterruptedException ex) { 88 System.err.println("Exception while interrupting test process: " + ex.getMessage()); 89 } 90 if (resultThread.isAlive()) { 91 resultThread.interrupt(); 92 } 93 super.interrupt(status); 94 } 95 96 @Override 97 protected synchronized Status getStatus() { 98 return super.getStatus(); 99 } 100 101 @Override 102 protected void before(TestDescription description, String resultDir) throws Throwable { 103 String testClassName = td.getParameter(RunUITestFinder.UNIT_TEST_CLASS_NAME); 104 String testName = td.getParameter(RunUITestFinder.TEST_NAME); 105 final String runMode = savedEnv.lookup(BasicFXInterview.RUN_MODE_PARAM)[0]; 106 107 System.out.println("\nTEST: " + testClassName + "/" + testName); 108 System.out.println("Mode:" + runMode); 109 System.out.println("Result Dir:" + resultDir); 110 if (needToRun(testClassName, testName, runMode)) { 111 112 try { 113 int masterPort = startServer(); 114 115 if (runMode.equals(BasicFXInterview.RUN_MODE_DESKTOP) 116 || runMode.equals(BasicFXInterview.RUN_MODE_DESKTOP_SWING_INTEROPERABILITY) 117 || runMode.equals(BasicFXInterview.RUN_MODE_DESKTOP_SWT_INTEROPERABILITY)) { 118 runTd(description, resultDir, masterPort); 119 } else { 120 runPlugin(td, resultDir, BasicFXInterview.RUN_MODE_JNLP.equals(runMode)); 121 } 122 } catch (Throwable e) { 123 e.printStackTrace(System.err); 124 if (cmdServer != null) { 125 try { 126 cmdServer.close(); 127 } catch (IOException ex) { 128 ex.printStackTrace(System.err); 129 } 130 } 131 if (cmdSocket != null) { 132 try { 133 cmdSocket.close(); 134 } catch (IOException ex) { 135 ex.printStackTrace(System.err); 136 } 137 } 138 if (commandStream != null) { 139 try { 140 commandStream.close(); 141 } catch (IOException ex) { 142 ex.printStackTrace(System.err); 143 } 144 } 145 if (process != null) { 146 process.destroy(); 147 } 148 commandStream.close(); 149 interrupt(Status.error(e.toString())); 150 } 151 152 resultThread = new Thread(new Runnable() { 153 @Override 154 public void run() { 155 try { 156 System.err.println("Waiting for exit"); 157 ObjectInputStream ois = new ObjectInputStream(cmdSocket.getInputStream()); 158 status = (TestRunner.Status) ois.readObject(); 159 160 Status jtStatus; 161 System.err.println("Process returned status " + status); 162 if (status == null) { 163 jtStatus = Status.error("Unexpected status: " + status); 164 } else if (status.isPassed()) { 165 jtStatus = Status.passed(status.getText()); 166 } else if (status.isFailed()) { 167 jtStatus = Status.failed(status.getText()); 168 } else { 169 jtStatus = Status.error(status.getText()); 170 } 171 interrupt(jtStatus); 172 173 } catch (Throwable ex) { 174 ex.printStackTrace(System.err); 175 interrupt(Status.error(CtrUtils.stackTraceToString(ex))); 176 } finally { 177 178 //finalize 179 try { 180 commandStream.close(); 181 cmdSocket.close(); 182 cmdServer.close(); 183 } catch (IOException ex) { 184 ex.printStackTrace(); 185 } 186 187 if (runMode.equals(BasicFXInterview.RUN_MODE_PLUGIN)) { 188 System.err.println("closing browser"); 189 if (process != null) { 190 process.destroy(); 191 } 192 } 193 try { 194 if (process != null) { 195 process.waitFor(); 196 } 197 } catch (InterruptedException ex) { 198 ex.printStackTrace(System.err); 199 } 200 // if (jemmyProcess != null) { 201 // System.out.println("killed jemmy process"); 202 // try { 203 // jemmyProcess.getInputStream().close(); 204 // } catch (IOException ex) { 205 // ex.printStackTrace(); 206 // } 207 // 208 // jemmyProcess.destroy(); 209 // } 210 System.out.println("DONE"); 211 } 212 } 213 }, "I'm waiting for test's result"); 214 resultThread.start(); 215 } 216 } 217 218 @Override 219 protected void showTestDialog(TestDescription td, TestEnvironment env) { 220 String nodescription = td.getParameter(RunUITestFinder.NO_DESCRIPTION); 221 boolean dryRun = YesNoQuestion.YES.equals(lookup(BasicFXInterview.DRY_RUN_TAG, YesNoQuestion.NO)); 222 if (!Boolean.parseBoolean(nodescription)) { 223 if (dryRun) { 224 System.err.println("DRY RUN MODE"); 225 int delay = Integer.parseInt(lookup(BasicFXInterview.DRY_RUN_DURATION_TAG, BasicFXInterview.DRY_RUN_DURATION_TAG.toString())); 226 try { 227 Thread.sleep(delay * 1000); 228 } catch (InterruptedException ex) { 229 } 230 setStatus(Status.error("Dry Run")); 231 } else { 232 super.showTestDialog(td, env); 233 } 234 } 235 } 236 237 /** 238 * Never put any cleanup here as this method would be called only in case of 239 * success 240 * @throws java.lang.Throwable 241 */ 242 @Override 243 protected void after(TestDescription description, String resultDir) throws Throwable { 244 } 245 246 @Override 247 public Status run(String[] args, TestDescription td, TestEnvironment env) { 248 savedEnv = env; 249 try { 250 String testClassName = td.getParameter(RunUITestFinder.UNIT_TEST_CLASS_NAME); 251 String testName = td.getParameter(RunUITestFinder.TEST_NAME); 252 final String runMode = savedEnv.lookup(BasicFXInterview.RUN_MODE_PARAM)[0]; 253 if (!needToRun(testClassName, testName, runMode)) { 254 return Status.passed("Not run in " + runMode + " mode"); 255 } 256 } catch (RunModes.RunModeException ex) { 257 return Status.error(ex.toString()); 258 } catch (NoSuchMethodException ex) { 259 return Status.error(ex.toString()); 260 } catch (ClassNotFoundException ex) { 261 return Status.error(ex.toString()); 262 } catch (Fault ex) { 263 return Status.error(ex.toString()); 264 } 265 super.run(args, td, env); 266 String hasCheckUI = td.getParameter(RunUITestFinder.HAS_CHECK_UI); 267 try { 268 if (Boolean.parseBoolean(hasCheckUI)) { 269 sendCommand(CommandType.CHECK_UI_AND_EXIT); 270 } else { 271 try { 272 sendCommand(CommandType.EXIT); 273 } catch (IOException ex) { 274 //this is valid for UI to exit before we asked for 275 } 276 } 277 resultThread.join(600000); 278 if (status == null) { 279 sendCommand(CommandType.ABORT); 280 setStatus(Status.error("process didn't return valid status")); 281 } 282 } catch (Throwable ex) { 283 return Status.error(ex.toString()); 284 } 285 286 System.out.println("We are done with " + td.getName() + ". Status: " + getStatus()); 287 return getStatus(); 288 } 289 290 private String getJvmArgPrismOrder() { 291 final String pipelineOptions = lookup(PipelineQuestion.PIPELINE_PARAM_NAME, ""); 292 String jvmArgPrismOrder = ""; 293 if (!pipelineOptions.trim().equals("")) { 294 jvmArgPrismOrder = "-Dprism.order=" + pipelineOptions; 295 } 296 return jvmArgPrismOrder; 297 } 298 299 /** 300 * 301 * @param td 302 * @param resultDir 303 * @return 304 * @throws IOException 305 * @throws Fault 306 */ 307 protected String[] tdCmdArgs(TestDescription td, String resultDir, int port) throws IOException, Fault { 308 String testClassName = td.getParameter(RunUITestFinder.UNIT_TEST_CLASS_NAME); 309 310 boolean isJunit = Boolean.parseBoolean(td.getParameter(RunUITestFinder.TYPE_JUNIT)); 311 312 //String fxSdkHome = td.getParameter(BasicFXInterview.FX_SDK_HOME_PARAM_NAME); 313 String fxSdkHome = savedEnv.lookup(BasicFXInterview.FX_SDK_HOME_PARAM_NAME)[0]; 314 315 String[] pathArr = savedEnv.lookup(BasicFXInterview.JAVA_PARAM_NAME); 316 StringBuilder pathStr = new StringBuilder(); 317 for (String p : pathArr) { 318 if (pathStr.length() > 0) { 319 pathStr.append(" "); 320 } 321 pathStr.append(p); 322 } 323 String javaExec = pathStr.toString(); 324 325 326 String proxy = lookup(BasicFXInterview.PROXY_PARAM_NAME, ""); 327 String jvmProxyHost = ""; 328 String jvmProxyPort = ""; 329 if (proxy != null && proxy.trim().length() > 0) { 330 URL proxyUrl = getProxyUrl(proxy); 331 if (proxyUrl != null) { 332 jvmProxyHost = "-DproxyHost=" + proxyUrl.getHost(); 333 jvmProxyPort = "-DproxyPort=" + proxyUrl.getPort(); 334 } 335 } 336 337 String additionalOptions = getAdditionalOptions(); 338 339 String[] jvmVmOptions = savedEnv.lookup(BasicFXInterview.VM_OPTIONS_PARAM_NAME); 340 341 String[] xPatch = savedEnv.lookup(BasicFXInterview.XPATCH_PARAM_NAME); 342 String xPatchArg = ""; 343 if (xPatch != null && xPatch.length > 0) { 344 File xPatchFile = new File(xPatch[0]); 345 xPatchArg = xPatchFile.getAbsolutePath(); 346 } 347 348 boolean enableAddExports = YesNoQuestion.YES.equals(lookup( 349 BasicFXInterview.ENABLE_ADD_EXPORTS_PARAM_NAME, YesNoQuestion.NO)); 350 351 String noAddExportsArg = enableAddExports ? null : "-DnoAddExports=true"; 352 353 String addExportsArg[] = enableAddExports 354 ? combineAddExports( 355 savedEnv.lookup(BasicFXInterview.ADD_EXPORTS_PARAM_NAME), 356 td.getParameter(RunUITestFinder.ADD_EXPORTS)) 357 : null; 358 359 String jvmArgPrismOrder = getJvmArgPrismOrder(); 360 361 362 // String externaloutput = lookup(BasicFXInterview.EXTERNALOUTPUT, ""); 363 // if (externaloutput != null) { 364 // jvmArgImageUtils = "-Dimageutils.outputpath=" + externaloutput + File.separator; 365 // } 366 String jvmArgImageUtils = "-Dimageutils.outputpath=" + resultDir + File.separator; 367 368 String jvmArgNoDesc = ""; 369 if (Boolean.parseBoolean(td.getParameter(RunUITestFinder.NO_DESCRIPTION))) { 370 jvmArgNoDesc = "-Djavatest.mode.nodesc=true"; 371 } 372 373 String runMode = lookup(BasicFXInterview.RUN_MODE_PARAM, BasicFXInterview.RUN_MODE_DESKTOP); 374 375 String jvmInterop = ""; 376 if (runMode.equals(BasicFXInterview.RUN_MODE_DESKTOP_SWING_INTEROPERABILITY)) { 377 jvmInterop = "-Djavafx.swinginteroperability=true"; 378 } else if (runMode.equals(BasicFXInterview.RUN_MODE_DESKTOP_SWT_INTEROPERABILITY)) { 379 jvmInterop = "-Djavafx.swtinteroperability=true"; 380 } 381 382 String lookAndFeelOptions = ""; 383 String lfOptions = lookup(LookAndFeelQuestion.LOOKANDFEEL_PARAM_NAME, ""); 384 if (!lfOptions.trim().equals("")) { 385 lookAndFeelOptions = "-Djavafx.userAgentStylesheetUrl=" + lfOptions; 386 } 387 388 //Needed to get images via proxy in Evergreen via VPN see RT-21325 || RT-19661 389 final boolean isFXCompatibility = System.getProperty("java.class.path").contains("JavaFXCompatibility"); 390 String ipV4 = isFXCompatibility ? "-Djava.net.preferIPv4Stack=true" : ""; 391 392 String swtTestOpt = ""; 393 try { 394 if (System.getProperty("os.name").toLowerCase().contains("mac")) { 395 RunWith wunWithAnnotation = Class.forName(testClassName).getAnnotation(RunWith.class); 396 if ((wunWithAnnotation != null) && (wunWithAnnotation.value().equals(CanvasRunner.class))) { 397 swtTestOpt = "-XstartOnFirstThread"; 398 System.out.println("Use -XstartOnFirstThread option, as we on MacOS, and SWT test is run."); 399 } 400 } 401 } catch (ClassNotFoundException ex) { 402 System.err.println("Error : " + ex); 403 } 404 405 String jvmArgClientTestRoot = "-DtestRoot=" + RunUITestFinder.testRoot; 406 407 String[] command = new String[]{}; 408 command = addToArray(command, javaExec.trim()); 409 command = addToArray(command, jvmVmOptions); 410 if (addExportsArg != null) { 411 command = addToArray(command, addExportsArg); 412 } else if (noAddExportsArg != null) { 413 command = addToArray(command, noAddExportsArg); 414 } 415 if (xPatchArg != null && !xPatchArg.isEmpty()) { 416 command = addToArray(command, "-Xpatch:" + xPatchArg); 417 } 418 command = addToArray(command, lookAndFeelOptions); 419 command = addToArray(command, ipV4); 420 command = addToArray(command, jvmArgPrismOrder, jvmArgImageUtils); 421 command = addToArray(command, additionalOptions); 422 command = addToArray(command, jvmArgNoDesc, jvmProxyHost, jvmProxyPort, jvmInterop, swtTestOpt); 423 command = addToArray(command, jvmArgClientTestRoot); 424 command = addToArray(command, "-DmasterPort=" + port); 425 command = addToArray(command, "-classpath", System.getProperty("java.class.path")); 426 // command = addToArray(command, "-Xdebug", "-Xnoagent", "-Djava.compiler=NONE", "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5858"); 427 command = addToArray(command, isJunit ? JUnit2TestRunner.class.getName() : TestRunner.class.getName(), testClassName); 428 return command; 429 } 430 431 static String[] combineAddExports(String[] addExportsArray, String addExportsValue) { 432 if (addExportsValue == null) { 433 return combineAddExports(addExportsArray); 434 } else { 435 String[] newArray = new String[addExportsArray.length + 1]; 436 System.arraycopy(addExportsArray, 0, newArray, 1, addExportsArray.length); 437 newArray[0] = addExportsValue; 438 return combineAddExports(newArray); 439 } 440 } 441 442 static String[] combineAddExports(String[] addExportsArray) { 443 List<String> addExportsList = new ArrayList<>(); 444 for (String addExports : addExportsArray) { 445 if (addExports != null) { 446 for (String value : addExports.split("\\s*,\\s*")) { 447 if (!value.isEmpty() && !addExportsList.contains(value.trim())) { 448 addExportsList.add("--add-exports"); 449 addExportsList.add(value.trim()); 450 addExportsList.add("--add-opens"); 451 addExportsList.add(value.trim()); 452 } 453 } 454 } 455 } 456 return addExportsList.toArray(new String[addExportsList.size()]); 457 } 458 459 460 /** 461 * 462 * @param td 463 * @param resultDir 464 * @return 465 */ 466 protected String[] pluginCmdArgs(TestDescription td, String resultDir) { 467 return null; 468 } 469 470 /** 471 * 472 * @param command 473 * @throws IOException 474 */ 475 protected void doRunTd(String[] command) throws IOException { 476 process = Runtime.getRuntime().exec(deleteEmptyElements(command)); 477 } 478 479 private int startServer() throws IOException { 480 System.out.println("Starting server." ); 481 int iRetryCount = 3; 482 boolean bindDone = false; 483 while ( (iRetryCount > 0) && (false==bindDone) ) { 484 iRetryCount = iRetryCount - 1; 485 486 try { 487 cmdServer = new ServerSocket(0); 488 System.out.println("Started server at port " + cmdServer.getLocalPort()); 489 bindDone = true; 490 } catch (java.net.BindException be) { 491 bindDone = false; 492 System.out.println(" === bind exception ==="); 493 Socket socket = new Socket("127.0.0.1", cmdServer.getLocalPort()); 494 commandStream = new ObjectOutputStream(socket.getOutputStream()); 495 sendCommand(CommandType.ABORT); 496 try {Thread.sleep(100);} catch(Exception e){} 497 } 498 499 }// retry loop end 500 cmdServer.setSoTimeout(60000); // we need to be generous for plugin mode, it gets to "download" runnable 501 return cmdServer.getLocalPort(); 502 } 503 504 private void waitForConnection() throws IOException { 505 System.out.println("Waiting for connection..."); 506 cmdSocket = cmdServer.accept(); 507 commandStream = new ObjectOutputStream(cmdSocket.getOutputStream()); 508 System.out.println("Connected"); 509 } 510 511 private void sendCommand(CommandType command) throws UnknownHostException, IOException { 512 sendCommand(command, "-"); 513 } 514 515 private synchronized void sendCommand(CommandType command, String param) throws IOException { 516 Command trc = new Command(command, param); 517 if (verbose) { 518 System.out.println("command " + trc); 519 } 520 commandStream.writeObject(trc); 521 } 522 523 /** 524 * 525 * @param id 526 * @param def 527 * @return 528 */ 529 protected String lookup(String id, String def) { 530 String[] result = null; 531 try { 532 result = savedEnv.lookup(id); 533 } catch (Fault ex) { 534 ex.printStackTrace(System.err); 535 } 536 return result == null || result.length == 0 ? def : result[0]; 537 } 538 539 /** 540 * 541 * @param id 542 * @return 543 */ 544 protected String[] lookup(String id) { 545 String[] result = null; 546 try { 547 result = savedEnv.lookup(id); 548 } catch (Fault ex) { 549 ex.printStackTrace(System.err); 550 } 551 return result; 552 } 553 554 private void runTd(TestDescription td, String resultDir, int port) throws IOException, InterruptedException, Fault { 555 String[] command = tdCmdArgs(td, resultDir, port); 556 dumpProcessExecution(resultDir, command, null); 557 doRunTd(command); 558 System.out.println("Logs: " + resultDir + File.separator); 559 560 if (process != null) { 561 //TODO: who close that streams? 562 new Thread(new OutputReader(new FileOutputStream(resultDir + File.separator + "process.out"), process.getInputStream())).start(); 563 new Thread(new OutputReader(new FileOutputStream(resultDir + File.separator + "process.err"), process.getErrorStream())).start(); 564 } else { 565 System.out.println("ERROR: Failed to create process"); // TODO: fail test? 566 } 567 waitForConnection(); 568 String testName = td.getParameter(RunUITestFinder.TEST_NAME); 569 String testClassName = td.getParameter(RunUITestFinder.UNIT_TEST_CLASS_NAME); 570 sendCommand(CommandType.SET_TEST_CLASS, testClassName); 571 if (testName != null) { 572 sendCommand(CommandType.SET_TEST_NAME, testName); 573 } 574 sendCommand(CommandType.RUN_TEST); 575 } 576 577 private static void dumpProcessExecution(String resultDir, String[] cmd, String workdir) throws IOException { 578 final PrintWriter writer = new PrintWriter( 579 new FileWriter(resultDir + File.separator + "process_execution.log")); 580 writer.println("starting process..."); 581 writer.println("Command: "); 582 for (String s : cmd) { 583 writer.print(s); 584 writer.print("\n"); 585 } 586 writer.println(""); 587 if (workdir != null) { 588 writer.println("Workdir: " + workdir); 589 } 590 writer.flush(); 591 } 592 private static final String pluginPath = "./dist-plugin/"; 593 private static final String pluginFile = "JavaClientPluginTest"; 594 595 private void runPlugin(TestDescription td, String resultDir, boolean isJnlp) 596 throws IOException, Fault { 597 String testClassName = td.getParameter(RunUITestFinder.UNIT_TEST_CLASS_NAME); 598 String testName = td.getParameter(RunUITestFinder.TEST_NAME); 599 600 //TODO: add non-junit tests support 601 boolean isJunit = Boolean.parseBoolean(td.getParameter(RunUITestFinder.TYPE_JUNIT)); 602 if (!isJunit) { 603 throw new UnsupportedOperationException("runui is not supported yet"); 604 } 605 String[] command; 606 String param; 607 File workdir = new File(System.getProperty("user.dir")); 608 final int port = 8485; 609 if (isJnlp) { 610 String[] pathArr = savedEnv.lookup(BasicFXInterview.JAVAWS_PARAM_NAME); 611 StringBuilder pathStr = new StringBuilder(); 612 for (String p : pathArr) { 613 if (pathStr.length() > 0) { 614 pathStr.append(" "); 615 } 616 pathStr.append(p); 617 } 618 File path = new File(pathStr.toString()); 619 param = new File(pluginPath + pluginFile + ".jnlp").getAbsolutePath(); 620 if (!path.exists()) { 621 throw new IllegalArgumentException("javaws path is invalid: " + pathStr); 622 } 623 workdir = path.getParentFile(); 624 625 String jvmArgPrismOrder = getJvmArgPrismOrder(); 626 if (jvmArgPrismOrder.length() > 0) { 627 command = new String[]{pathStr.toString(), "-J" + jvmArgPrismOrder}; // "-Dprism.order=sw" 628 } else { 629 command = new String[]{pathStr.toString()}; 630 } 631 632 } else { // plugin 633 command = addBrowserTricks(savedEnv.lookup(BasicFXInterview.BROWSER_PARAM_NAME)); 634 JettyServer.getInstance(port).setBaseDir(new File(pluginPath).getAbsolutePath()); 635 param = "http://localhost:" + port + "/" + pluginFile + ".html"; 636 } 637 if (verbose) { 638 for (String string : command) { 639 System.err.println("cmd: " + string); 640 } 641 } 642 String[] merge = addToArray(command, param); 643 dumpProcessExecution(resultDir, merge, workdir.getAbsolutePath()); 644 if (Utils.isMacOS()) { 645 ensureJemmyServerRun(workdir.getAbsolutePath()); 646 } 647 process = new ProcessBuilder(merge).directory(workdir).start(); 648 if (process == null) { 649 throw new RuntimeException("Failed to create process for test "); 650 } 651 waitForConnection(); 652 sendCommand(CommandType.SET_OUT, resultDir + File.separator + "process.out"); 653 sendCommand(CommandType.SET_ERR, resultDir + File.separator + "process.err"); 654 sendCommand(CommandType.SET_TEST_CLASS, testClassName); 655 sendCommand(CommandType.SET_BASEDIR, System.getProperty("user.dir")); 656 sendCommand(CommandType.SET_ABSOLUTE_DIR, resultDir + File.separator); 657 if (testName != null) { 658 sendCommand(CommandType.SET_TEST_NAME, testName); 659 } 660 sendCommand(CommandType.RUN_TEST); 661 } 662 663 /** 664 * 665 * @param arr 666 * @param st 667 * @return 668 */ 669 public static String[] addToArray(String[] arr, String... st) { 670 String[] newArr = new String[arr.length + st.length]; 671 System.arraycopy(arr, 0, newArr, 0, arr.length); 672 System.arraycopy(st, 0, newArr, arr.length, st.length); 673 return newArr; 674 } 675 676 private static enum BROWSER { 677 678 FIREFOX("firefox"), CHROME("chrome"), IE("iexplore"), SAFARI("safari"), UNKNOWN("\n"); 679 private final String key; 680 681 private BROWSER(String key) { 682 this.key = key; 683 } 684 685 public static BROWSER detect(String[] command) { 686 for (int i = command.length - 1; i >= 0; i--) { 687 for (BROWSER browser : values()) { 688 if (command[i] != null && command[i].toLowerCase().contains(browser.key)) { 689 System.out.println("Detected Browser: " + browser.name()); 690 return browser; 691 } 692 } 693 } 694 return UNKNOWN; 695 } 696 }; 697 698 private static String[] addBrowserTricks(String[] command) { 699 switch (BROWSER.detect(command)) { 700 case CHROME: 701 return addToArray(command, "--kiosk", "--incognito", "--disable-hang-monitor", "--always-authorize-plugins", "--allow-outdated-plugins"); 702 case FIREFOX: 703 return addToArray(command, "-new-window"); 704 case IE: 705 return addToArray(command, "-k"); 706 case SAFARI: 707 return new String[]{"/usr/bin/open", "-a", "Safari"}; 708 } 709 return command; 710 } 711 712 private boolean needToRun(String testClassName, String testName, String runMode) throws NoSuchMethodException, ClassNotFoundException, RunModeException { 713 Class testClass = Class.forName(testClassName); 714 RunModes mode = RunModes.parseString(runMode); 715 if (mode == null) { 716 throw new RunModes.RunModeException(runMode); 717 } 718 ExcludeRunModeType ermt = (ExcludeRunModeType) testClass.getAnnotation(ExcludeRunModeType.class); 719 if (ermt != null) { 720 if (ermt.value() == mode) { 721 return false; 722 } 723 } 724 OnlyRunModeType ormt = (OnlyRunModeType) testClass.getAnnotation(OnlyRunModeType.class); 725 if (ormt != null) { 726 if (ormt.value() != mode) { 727 return false; 728 } 729 } 730 if (testName == null) { 731 // fox JavaFXCompatibility suite weird run mode 732 return true; 733 } 734 //not testClass.getMethod(testName) because we can't get static method. 735 Method[] methods = testClass.getMethods(); 736 for (Method testMethod : methods) { 737 if (testName.equals(testMethod.getName())) { 738 ExcludeRunModeMethod ermm = (ExcludeRunModeMethod) testMethod.getAnnotation(ExcludeRunModeMethod.class); 739 if (ermm != null) { 740 if (ermm.value() == mode) { 741 return false; 742 } 743 } 744 OnlyRunModeMethod ormm = (OnlyRunModeMethod) testMethod.getAnnotation(OnlyRunModeMethod.class); 745 if (ormm != null) { 746 if (ormm.value() != mode) { 747 return false; 748 } 749 } 750 } 751 } 752 return true; 753 } 754 755 /** 756 * 757 * @return 758 */ 759 public Thread getProcessKiller() { 760 return new ProcessKiller(5000L, process, cmdServer, cmdSocket); 761 } 762 763 private class ProcessKiller extends Thread { 764 765 long sleepTime; 766 Process targetProc; 767 ServerSocket targetSerSocket; 768 Socket targetSocket; 769 770 public ProcessKiller(long time, Process process, ServerSocket targetSerSock, Socket targetSock) { 771 this.sleepTime = time; 772 this.targetProc = process; 773 this.targetSerSocket = targetSerSock; 774 this.targetSocket = targetSock; 775 } 776 777 @Override 778 public void run() { 779 try { 780 sleep(sleepTime); 781 } catch (InterruptedException ex) { 782 Logger.getLogger(TestScript.class.getName()).log(Level.SEVERE, null, ex); 783 } 784 if (targetProc.isAlive()) { 785 System.out.println("Process has been interrupted forcibly!"); 786 targetProc.destroyForcibly(); 787 if (targetSerSocket != null) { 788 if (!targetSerSocket.isClosed()) { 789 try { 790 targetSerSocket.close(); 791 } catch (IOException ex) { 792 System.out.println("CMDSERVER: exception while cloing"); 793 ex.printStackTrace(); 794 } 795 } 796 } else { 797 System.out.println("CMDSERVER: NULL"); 798 } 799 if (targetSocket != null) { 800 if (!targetSocket.isClosed()) { 801 try { 802 targetSocket.close(); 803 } catch (IOException ex) { 804 System.out.println("CMDSOCKET: exception while cloing"); 805 ex.printStackTrace(); 806 } 807 } 808 } else { 809 System.out.println("CMDSOCKET: NULL"); 810 } 811 } 812 } 813 } 814 815 /** 816 * 817 * @return 818 */ 819 protected TestEnvironment getSavedEnv() { 820 return savedEnv; 821 } 822 823 /** 824 * 825 * @return 826 */ 827 protected String getAdditionalOptions(){ 828 return ""; 829 } 830 831 }