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 client.test.runner.interview.LookAndFeelQuestion; 28 import client.test.runner.interview.PipelineGroupQuestion; 29 import client.util.CtrUtils; 30 import com.sun.interview.*; 31 import com.sun.javatest.Parameters.EnvParameters; 32 import com.sun.javatest.TestEnvironment; 33 import com.sun.javatest.interview.BasicInterviewParameters; 34 import java.io.File; 35 import java.io.IOException; 36 import java.net.UnknownHostException; 37 import java.util.HashMap; 38 import java.util.Map; 39 40 /** 41 * 42 * @author vshubov 43 */ 44 public class BasicFXInterview extends BasicInterviewParameters 45 implements EnvParameters { 46 47 /** 48 * 49 */ 50 public final static String FX_SDK_HOME_PARAM_NAME = "javafx"; 51 52 /** 53 * 54 */ 55 public final static String EXTERNALOUTPUT = "externaloutput"; 56 57 /** 58 * 59 */ 60 public final static String PROXY_PARAM_NAME = "proxy"; 61 62 /** 63 * 64 */ 65 public final static String DRY_RUN_TAG = "dryrun"; 66 67 /** 68 * 69 */ 70 public final static String DRY_RUN_DURATION_TAG = "dryrun_duration"; 71 72 /** 73 * 74 */ 75 public static final String REMOTE_RUN = "remote"; 76 77 /** 78 * 79 */ 80 public static final String JAVATEST_HOSTNAME = "hostname"; 81 82 /** 83 * 84 */ 85 public static final String RUN_MODE_PARAM = "runmode"; 86 87 /** 88 * 89 */ 90 public static final String RUN_MODE_DESKTOP = "desktop"; 91 92 /** 93 * 94 */ 95 public static final String RUN_MODE_DESKTOP_SWING_INTEROPERABILITY = "swing_interoperability"; 96 97 /** 98 * 99 */ 100 public static final String RUN_MODE_DESKTOP_SWT_INTEROPERABILITY = "swt_interoperability"; 101 102 /** 103 * 104 */ 105 public static final String RUN_MODE_PLUGIN = "plugin"; 106 107 /** 108 * 109 */ 110 public static final String RUN_MODE_JNLP = "jnlp"; 111 112 /** 113 * 114 */ 115 public final static String BROWSER_PARAM_NAME = "browserPath"; 116 117 /** 118 * 119 */ 120 public final static String JAVAWS_PARAM_NAME = "javawsPath"; 121 122 /** 123 * 124 */ 125 public final static String JAVA_PARAM_NAME = "javaPath"; 126 127 /** 128 * 129 */ 130 public final static String VM_OPTIONS_PARAM_NAME = "vmOptions"; 131 132 /** 133 * 134 */ 135 public final static String TESTSUITE_ID = "testsuiteID"; 136 137 private String javaFXHome; 138 private String extOut; 139 140 /** 141 * 142 * @throws Fault 143 */ 144 public BasicFXInterview() throws Fault { 145 super(null); 146 } 147 148 /** 149 * 150 * @return 151 */ 152 @Override 153 protected Question getEnvFirstQuestion() { 154 return qName; 155 } 156 157 /** 158 * 159 * @return 160 */ 161 @Override 162 public EnvParameters getEnvParameters() { 163 return this; 164 } 165 166 /** 167 * 168 * @return 169 */ 170 @Override 171 public TestEnvironment getEnv() { 172 HashMap envProps = new HashMap(); 173 export(envProps); 174 try { 175 String name = qName.getValue(); 176 if (name == null || name.length() == 0) { 177 name = "unknown"; 178 } 179 return new TestEnvironment(name, envProps, "configuration interview"); 180 } catch (TestEnvironment.Fault e) { 181 throw new Error("should not happen" + e); 182 } 183 } 184 185 /** 186 * 187 * @param data 188 */ 189 @Override 190 public void export(Map data) { 191 String id = getTestSuite().getTestSuiteInfo("id"); 192 data.put(TESTSUITE_ID, id); 193 super.export(data); 194 } 195 196 /** 197 * 198 * @return 199 */ 200 public boolean isRemoteRun() { 201 return YesNoQuestion.YES.equals(qRemoteRun.getValue()); 202 } 203 204 /** 205 * 206 * @return 207 */ 208 public File getJavaPath(){ 209 return qJavaPath.getValue(); 210 } 211 212 /** 213 * 214 * @return 215 */ 216 protected Question getLastQuestion(){ 217 return getEnvSuccessorQuestion(); 218 } 219 220 /** 221 * 222 */ 223 protected StringQuestion qName = new StringQuestion(this, "name") { 224 @Override 225 public String getText() { 226 return getSummary(); 227 } 228 229 @Override 230 public String getSummary() { 231 return "Configuration name"; 232 } 233 234 @Override 235 public Question getNext() { 236 if ("".equals(getValue()) || getValue() == null) { 237 return null; 238 } 239 return qRemoteRun; 240 } 241 242 @Override 243 public void export(Map data) { 244 data.put("name", value); 245 } 246 247 @Override 248 public void load(Map data) { 249 setValue((String) data.get("name")); 250 } 251 }; 252 private YesNoQuestion qRemoteRun = new YesNoQuestion(this, REMOTE_RUN, YesNoQuestion.NO) { 253 @Override 254 public String getText() { 255 return "Remote test execution: please specify whether you want to run the tests on a remote host." 256 + "The agent should be run on that host first."; 257 } 258 259 @Override 260 public String getSummary() { 261 return "Remote test execution"; 262 } 263 @Override 264 public Question getNext() { 265 if (YesNoQuestion.YES.equals(getValue())) { 266 return qHostName; 267 } 268 return qRunMode; 269 } 270 271 @Override 272 public void clear() { 273 setValue("No"); 274 } 275 276 @Override 277 protected void export(Map data) { 278 data.put(REMOTE_RUN, getValue()); 279 } 280 }; 281 private StringQuestion qHostName = new StringQuestion(this, JAVATEST_HOSTNAME) { 282 283 @Override 284 public String getText() { 285 return "Enter the name of the host you are currently running Javatest harness"; 286 } 287 288 @Override 289 public String getSummary() { 290 return "Javatest Host Name"; 291 } 292 293 @Override 294 public void clear() { 295 String host = "localhost"; 296 try { 297 host = java.net.InetAddress.getLocalHost().getHostAddress(); 298 } catch (UnknownHostException ex) { 299 //just ignore 300 } 301 setValue(host); 302 } 303 304 @Override 305 public Question getNext() { 306 return qRunMode; 307 } 308 309 @Override 310 public void export(Map data) { 311 data.put(JAVATEST_HOSTNAME, value); 312 } 313 }; 314 315 private ChoiceQuestion qRunMode = new ChoiceQuestion(this, RUN_MODE_PARAM) { 316 { 317 setChoices(new String[]{RUN_MODE_DESKTOP, RUN_MODE_DESKTOP_SWING_INTEROPERABILITY, RUN_MODE_DESKTOP_SWT_INTEROPERABILITY, RUN_MODE_PLUGIN, RUN_MODE_JNLP}, false); 318 clear(); 319 } 320 321 @Override 322 public Question getNext() { 323 if (RUN_MODE_PLUGIN.equals(getValue())) { 324 return qBrowser; 325 } else if (RUN_MODE_JNLP.equals(getValue())) { 326 return qJavawsPath; 327 } else { 328 return qJavaPath; 329 } 330 } 331 332 @Override 333 public String getDefaultValue() { 334 return RUN_MODE_DESKTOP; 335 } 336 337 @Override 338 public String getText() { 339 return "Test Run Mode: desktop or web based.\n N.B.: For web-based modes RUNTIME installed to system " 340 + "would be used instead SDK (javafx.home). Make sure they are of the same version.\n" 341 + "Run 'javaws -uninstall' before running web-mode tests."; 342 } 343 344 @Override 345 public String getSummary() { 346 return "Test Run Mode"; 347 } 348 349 @Override 350 public void clear() { 351 setValue(RUN_MODE_DESKTOP); 352 } 353 354 @Override 355 public void export(Map map) { 356 map.put(RUN_MODE_PARAM, value); 357 } 358 359 @Override 360 public void load(Map data) { 361 setValue((String) data.get(RUN_MODE_PARAM)); 362 } 363 }; 364 365 private FileQuestion qBrowser = new FileQuestion(this, BROWSER_PARAM_NAME) { 366 { 367 this.setFilter(new ExecutablesFileFilter()); 368 } 369 370 @Override 371 public String getText() { 372 return "Choose browser executable. Please, close all instances of that browser prior to running tests."; 373 } 374 375 @Override 376 public String getSummary() { 377 return "Browser executable"; 378 } 379 380 @Override 381 public void export(Map data) { 382 data.put(BROWSER_PARAM_NAME, value.getPath()); 383 } 384 385 //TODO: browsers autodetection 386 private static final String FF = "firefox"; 387 388 @Override 389 protected void save(Map data) { 390 // this is not the best place to perform this check, but javatest doesn't provide better option 391 String path = value.getPath(); 392 if (path != null && path.contains("iexplore")) { 393 BasicFXInterview.ieFix.run(); 394 } 395 super.save(data); 396 } 397 398 private final String mostCommonPaths[] = new String[]{ 399 "\\Applications\\Firefox.app\\Contents\\MacOS\\firefox", 400 "C:/Program Files (x86)/Mozilla Firefox/firefox.exe" 401 }; 402 403 @Override 404 public void clear() { 405 String def = FF; 406 for (String path : mostCommonPaths) { 407 File f = new File(path); 408 if (f.isFile()) { 409 setValue(f.getAbsolutePath()); 410 return; 411 } 412 } 413 setValue(def); 414 } 415 416 @Override 417 public Question getNext() { 418 if (!(value.isFile() || FF.equals(value.getName()))) { 419 return null; 420 } 421 return getEnvSuccessorQuestion(); 422 } 423 424 @Override 425 public void load(Map data) { 426 427 String tmp = null; 428 if (data.containsKey(BROWSER_PARAM_NAME) 429 && (null!=(tmp= (String)data.get(BROWSER_PARAM_NAME))) 430 && (new File(tmp)).isFile() ) { 431 setValue(new File(tmp)); 432 } 433 else { 434 clear(); 435 } 436 } 437 438 }; 439 440 private FileQuestion qJavawsPath = new FileQuestion(this, JAVAWS_PARAM_NAME) { 441 { 442 this.setFilter(new ExecutablesFileFilter()); 443 } 444 445 @Override 446 public String getText() { 447 return "Choose javaws executable location."; 448 } 449 450 @Override 451 public String getSummary() { 452 return "Java Web Start Executable"; 453 } 454 private final String mostCommonPaths[] = new String[]{ 455 "C:/Program Files (x86)/Oracle/JavaFX Runtime 2.0/bin/javaws.exe", 456 "C:/Program Files/Oracle/JavaFX Runtime 2.0/bin/javaws.exe", 457 "C:/Program Files/Java/jdk1.8.0/jre/bin/javaws.exe", 458 "C:/Program Files (x86)/Java/jdk1.8.0/jre/bin/javaws.exe" 459 }; 460 private static final String JAVAWS = "javaws"; 461 462 @Override 463 public void clear() { // you should not call setValue() twice here, 464 // and should not ask why 465 String def = JAVAWS; 466 if (isWindows()) { 467 for (String path : mostCommonPaths) { 468 // debug System.out.println("try:" + path); 469 File f = new File(path); 470 if (f.isFile()) { 471 // debug System.out.println("Yes!" + f.getAbsolutePath()); 472 setValue(f.getAbsolutePath()); 473 // debug System.out.println("Yes=" + getValue()); 474 return; 475 } 476 } 477 } 478 setValue(def); 479 } 480 481 @Override 482 public Question getNext() { 483 return qPipelineGroup; 484 } 485 486 @Override 487 public void export(Map data) { 488 data.put(JAVAWS_PARAM_NAME, value.getPath()); 489 } 490 491 @Override 492 public void load(Map data) { 493 494 String tmp = null; 495 if (data.containsKey(JAVAWS_PARAM_NAME) 496 && (null!=(tmp= (String)data.get(JAVAWS_PARAM_NAME))) 497 && (new File(tmp)).isFile() ) { 498 setValue(new File(tmp)); 499 } 500 else { 501 clear(); 502 } 503 } 504 }; 505 506 private FileQuestion qJavaPath = new FileQuestion(this, JAVA_PARAM_NAME) { 507 { 508 this.setFilter(new ExecutablesFileFilter()); 509 } 510 511 @Override 512 public boolean isValueValid() { 513 if(YesNoQuestion.YES.equals(qRemoteRun.getValue())) { 514 return true; 515 } 516 return super.isValueValid(); 517 } 518 519 @Override 520 public String getText() { 521 return "Choose java executable from JDK installation."; 522 } 523 524 @Override 525 public String getSummary() { 526 return "Java Executable"; 527 } 528 private final String JAVA_DEF = System.getProperty("java.home") + File.separator + "bin" + File.separator + (isWindows() ? "java.exe":"java"); 529 530 @Override 531 public void clear() { 532 setValue(JAVA_DEF); 533 } 534 535 @Override 536 public Question getNext() { 537 return qJavaFX; 538 } 539 540 @Override 541 public void export(Map data) { 542 data.put(JAVA_PARAM_NAME, value.getPath()); 543 } 544 545 @Override 546 public void load(Map data) { 547 if (data.containsKey(JAVA_PARAM_NAME)) { 548 String exec = (String) data.get(JAVA_PARAM_NAME); 549 if (exec != null) { 550 setValue(new File(exec)); 551 } 552 } 553 } 554 }; 555 556 557 private FileQuestion qJavaFX = new FileQuestion(this, FX_SDK_HOME_PARAM_NAME) { 558 { 559 this.setFilter(new DirectoryFileFilter("JavaFX SDK containing directory")); 560 } 561 562 @Override 563 public String getText() { 564 return getSummary(); 565 } 566 567 @Override 568 public String getSummary() { 569 return "JavaFX SDK Home"; 570 } 571 572 @Override 573 public boolean isValueValid() { 574 if(YesNoQuestion.YES.equals(qRemoteRun.getValue())) { 575 return true; 576 } 577 return super.isValueValid(); 578 } 579 580 @Override 581 public void clear() { 582 if (javaFXHome != null) { 583 setValue(javaFXHome); 584 } else { 585 setValue(""); 586 } 587 } 588 589 @Override 590 public Question getNext() { 591 return qDryRun; 592 } 593 594 @Override 595 public void export(Map data) { 596 javaFXHome = value.getPath(); 597 data.put(FX_SDK_HOME_PARAM_NAME, javaFXHome); 598 } 599 600 @Override 601 public void load(Map data) { 602 if (data.containsKey(FX_SDK_HOME_PARAM_NAME)) { 603 javaFXHome = (String) data.get(FX_SDK_HOME_PARAM_NAME); 604 if (javaFXHome != null) { 605 setValue(new File(javaFXHome)); 606 } 607 } 608 } 609 }; 610 private YesNoQuestion qDryRun = new YesNoQuestion(this, DRY_RUN_TAG, YesNoQuestion.NO) { 611 @Override 612 public Question getNext() { 613 if (getValue().toString().equals(YES)) { 614 return qDryRunDuration; 615 } 616 return qExternalOutput; 617 } 618 619 @Override 620 public String getText() { 621 return "During dry run no tests' instructions are shown, only tests' UI. All tests are marked as ERROR. " 622 + "This is artificial mode used for debugging and other purposes. Doesn't affect automated tests."; 623 } 624 625 @Override 626 public String getSummary() { 627 return "Perform a Dry Run"; 628 } 629 630 @Override 631 public void export(Map data) { 632 data.put(DRY_RUN_TAG, getValue()); 633 } 634 635 @Override 636 public void load(Map data) { 637 if (data.containsKey(DRY_RUN_TAG)) { 638 setValue((String) data.get(DRY_RUN_TAG)); 639 } 640 } 641 }; 642 static final int DRY_RUN_DEFAULT_DELAY = 5; 643 private IntQuestion qDryRunDuration = new IntQuestion(this, DRY_RUN_DURATION_TAG, 0, 600) { 644 { 645 this.setDefaultValue(DRY_RUN_DEFAULT_DELAY); 646 } 647 648 @Override 649 protected Question getNext() { 650 return qExternalOutput; 651 } 652 653 @Override 654 public String getText() { 655 return "Setup duration of delay for closing test UI (in seconds)"; 656 } 657 658 @Override 659 public String getSummary() { 660 return "Dry Run delay"; 661 } 662 663 @Override 664 public void export(Map data) { 665 data.put(DRY_RUN_DURATION_TAG, Integer.toString(getValue())); 666 } 667 668 @Override 669 public void load(Map data) { 670 if (data.containsKey(DRY_RUN_DURATION_TAG)) { 671 try { 672 setValue(Integer.parseInt((String) data.get(DRY_RUN_DURATION_TAG))); 673 } catch (Exception e) { 674 // keep default 675 } 676 677 } 678 } 679 }; 680 private FileQuestion qExternalOutput = new FileQuestion(this, EXTERNALOUTPUT) { 681 @Override 682 public boolean isValueValid() { 683 if(YesNoQuestion.YES.equals(qRemoteRun.getValue())) { 684 return true; 685 } 686 return super.isValueValid(); 687 } 688 689 @Override 690 public Question getNext() { 691 return qLookAndFeelGroup; 692 } 693 694 @Override 695 public String getText() { 696 return getSummary(); 697 } 698 699 @Override 700 public String getSummary() { 701 return "output dir"; 702 } 703 704 @Override 705 public void export(Map data) { 706 extOut = value.getPath(); 707 data.put(EXTERNALOUTPUT, extOut); 708 } 709 710 @Override 711 public void load(Map data) { 712 if (data.containsKey(EXTERNALOUTPUT)) { 713 extOut = (String) data.get(EXTERNALOUTPUT); 714 if (extOut != null) { 715 setValue(new File(extOut)); 716 } 717 } 718 } 719 }; 720 721 private StringQuestion qProxy = new StringQuestion(this, "proxy") { 722 723 { 724 clear(); 725 } 726 @Override 727 public void clear() { 728 setValue(""); 729 } 730 731 @Override 732 public String getText() { 733 return "Proxy settings in format: host:port\nE.g. www-proxy.us.oracle.com:80"; 734 } 735 736 @Override 737 public String getSummary() { 738 return "Proxy settings"; 739 } 740 741 @Override 742 public Question getNext() { 743 String val = getValue(); 744 if (val == null || val.trim().length() == 0 || CtrUtils.getProxyUrl(val) != null) { 745 return qVmOptions; 746 } else { 747 return null; 748 } 749 } 750 751 @Override 752 public void export(Map data) { 753 data.put(PROXY_PARAM_NAME, value); 754 } 755 756 @Override 757 public void load(Map data) { 758 String v = (String) data.get(PROXY_PARAM_NAME); 759 setValue(v != null ? v : ""); 760 } 761 }; 762 763 private LookAndFeelQuestion qLookAndFeelGroup = new LookAndFeelQuestion (this, qProxy); 764 private ChoiceQuestion qPipelineGroup = new PipelineGroupQuestion (this, getLastQuestion()); 765 766 767 private static boolean isWindows() { 768 return System.getProperty("os.name").toLowerCase().contains("windows"); 769 } 770 private StringQuestion qVmOptions = new StringQuestion(this, VM_OPTIONS_PARAM_NAME) { 771 772 @Override 773 public String getText() { 774 return "Set VM Options for test run (desktop mode only).\nE.g. -Dprism.verbose=true"; 775 } 776 777 @Override 778 public String getSummary() { 779 return "VM Options"; 780 } 781 782 @Override 783 public void clear() { 784 setValue(""); 785 } 786 787 @Override 788 public Question getNext() { 789 return qPipelineGroup;//getLastQuestion(); 790 } 791 792 @Override 793 public void export(Map data) { 794 data.put(VM_OPTIONS_PARAM_NAME, value); 795 } 796 797 @Override 798 public void load(Map data) { 799 String newValue = (String) data.get(VM_OPTIONS_PARAM_NAME); 800 setValue(newValue != null ? newValue : ""); 801 } 802 }; 803 804 805 806 private static class ExecutablesFileFilter implements FileFilter { 807 @Override 808 public boolean accept(File file) { 809 return file.exists() && file.canExecute(); 810 } 811 812 @Override 813 public boolean acceptsDirectories() { 814 return false; 815 } 816 817 @Override 818 public String getDescription() { 819 return "Executable files"; 820 } 821 } 822 private static Runnable ieFix = new Runnable() { 823 @Override 824 public void run() { 825 if (!alreadyRun) { 826 alreadyRun = true; // we prefer this to be run only once but it's not big enough deal to introduce syncronization 827 System.out.println("NB: For internet explorer test run registry would be modified to run IE as one process and allow ActiveX from localhost."); 828 try { 829 System.out.println("'" + IE_TABS_LOCK_PATH + "\\" + IE_TABS_LOCK_KEY + "' key is being set to 0.\n"); 830 //TODO: in the perfect world we would read current value and restore it after test run 831 Runtime.getRuntime().exec("reg add \"" + IE_TABS_LOCK_PATH + "\" /v " + IE_TABS_LOCK_KEY + " /t REG_DWORD /d 0 /f"); 832 833 System.out.println("'" + IE_ACTIVEX_PATH + "\\" + IE_ACTIVEX_KEY + "' key is being set to 0.\n"); 834 Runtime.getRuntime().exec("reg add \"" + IE_ACTIVEX_PATH + "\" /v " + IE_ACTIVEX_KEY + " /t REG_DWORD /d 0 /f"); 835 836 System.out.println("'" + IE_ACTIVEX_LOCAL_PATH + "\\" + IE_ACTIVEX_LOCAL_KEY + "' key is being set to 0.\n"); 837 Runtime.getRuntime().exec("reg add \"" + IE_ACTIVEX_LOCAL_PATH + "\" /v " + IE_ACTIVEX_LOCAL_KEY + " /t REG_DWORD /d 0 /f"); 838 } catch (IOException ex) { 839 ex.printStackTrace(); 840 } 841 } 842 } 843 private boolean alreadyRun = false; 844 private static final String IE_TABS_LOCK_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Main"; 845 private static final String IE_TABS_LOCK_KEY = "TabProcGrowth"; 846 private static final String IE_ACTIVEX_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Safety\\ActiveXFiltering"; 847 private static final String IE_ACTIVEX_KEY = "IsEnabled"; 848 private static final String IE_ACTIVEX_LOCAL_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_LOCALMACHINE_LOCKDOWN"; 849 private static final String IE_ACTIVEX_LOCAL_KEY = "iexplore.exe"; 850 }; 851 852 }