1 package org.testng; 2 3 4 import java.io.BufferedReader; 5 import java.io.BufferedWriter; 6 import java.io.File; 7 import java.io.FileReader; 8 import java.io.FileWriter; 9 import java.io.IOException; 10 import java.net.MalformedURLException; 11 import java.net.URL; 12 import java.text.CharacterIterator; 13 import java.text.StringCharacterIterator; 14 import java.util.Enumeration; 15 import java.util.Iterator; 16 import java.util.List; 17 import java.util.Properties; 18 import java.util.StringTokenizer; 19 20 import org.apache.tools.ant.BuildException; 21 import org.apache.tools.ant.DirectoryScanner; 22 import org.apache.tools.ant.Project; 23 import org.apache.tools.ant.Target; 24 import org.apache.tools.ant.Task; 25 import org.apache.tools.ant.taskdefs.Execute; 26 import org.apache.tools.ant.taskdefs.ExecuteWatchdog; 27 import org.apache.tools.ant.taskdefs.LogOutputStream; 28 import org.apache.tools.ant.taskdefs.PumpStreamHandler; 29 import org.apache.tools.ant.types.Commandline; 30 import org.apache.tools.ant.types.CommandlineJava; 31 import org.apache.tools.ant.types.Environment; 32 import org.apache.tools.ant.types.FileSet; 33 import org.apache.tools.ant.types.Path; 34 import org.apache.tools.ant.types.PropertySet; 35 import org.apache.tools.ant.types.Reference; 36 import org.apache.tools.ant.types.ResourceCollection; 37 import org.apache.tools.ant.types.resources.FileResource; 38 import org.apache.tools.ant.types.selectors.FilenameSelector; 39 import org.testng.collections.Lists; 40 import org.testng.internal.Utils; 41 import org.testng.reporters.VerboseReporter; 42 43 import static java.lang.Boolean.TRUE; 44 import static org.testng.internal.Utils.isStringNotBlank; 45 46 /** 47 * TestNG settings: 48 * <ul> 49 * <li>classfileset (inner)</li> 50 * <li>classfilesetref (attribute)</li> 51 * <li>xmlfileset (inner)</li> 52 * <li>xmlfilesetref (attribute)</li> 53 * <li>enableAssert (attribute)</li> 54 * <li>excludedGroups (attribute)</li> 55 * <li>groups (attribute)</li> 56 * <li>junit (attribute)</li> 57 * <li>listener (attribute)</li> 58 * <li>outputdir (attribute)</li> 59 * <li>parallel (attribute)</li> 60 * <li>reporter (attribute)</li> 61 * <li>sourcedir (attribute)</li> 62 * <li>sourcedirref (attribute)</li> 63 * <li>suitename (attribute)</li> 64 * <li>suiterunnerclass (attribute)</li> 65 * <li>target (attribute)</li> 66 * <li>testjar (attribute)</li> 67 * <li>testname (attribute)</li> 68 * <li>threadcount (attribute)</li> 69 * <li>dataproviderthreadcount (attribute)</li> 70 * <li>verbose (attribute)</li> 71 * <li>testrunfactory (attribute)</li> 72 * <li>configFailurepolicy (attribute)</li> 73 * <li>randomizeSuites (attribute)</li> 74 * <li>methodselectors (attribute)</li> 75 * </ul> 76 * 77 * Ant settings: 78 * <ul> 79 * <li>classpath (inner)</li> 80 * <li>classpathref (attribute)</li> 81 * <li>jvm (attribute)</li> 82 * <li>workingDir (attribute)</li> 83 * <li>env (inner)</li> 84 * <li>sysproperty (inner)</li> 85 * <li>propertyset (inner)</li> 86 * <li>jvmarg (inner)</li> 87 * <li>timeout (attribute)</li> 88 * <li>haltonfailure (attribute)</li> 89 * <li>onHaltTarget (attribute)</li> 90 * <li>failureProperty (attribute)</li> 91 * <li>haltonFSP (attribute)</li> 92 * <li>FSPproperty (attribute)</li> 93 * <li>haltonskipped (attribute)</li> 94 * <li>skippedProperty (attribute)</li> 95 * <li>testRunnerFactory (attribute)</li> 96 * </ul> 97 * 98 * Debug information: 99 * <ul> 100 * <li>dumpCommand (boolean)</li> 101 * <li>dumpEnv (boolean)</li> 102 * <li>dumpSys (boolean)</li> 103 * </ul> 104 * 105 * @author <a href="mailto:the_mindstorm@evolva.ro">Alexandru Popescu</a> 106 * @author Cedric Beust 107 * @author Lukas Jungmann 108 */ 109 public class TestNGAntTask extends Task { 110 111 protected CommandlineJava m_javaCommand; 112 113 protected List<ResourceCollection> m_xmlFilesets= Lists.newArrayList(); 114 protected List<ResourceCollection> m_classFilesets= Lists.newArrayList(); 115 protected File m_outputDir; 116 protected File m_testjar; 117 protected File m_workingDir; 118 private Integer m_timeout; 119 private List<String> m_listeners= Lists.newArrayList(); 120 private List<String> m_methodselectors= Lists.newArrayList(); 121 private String m_objectFactory; 122 protected String m_testRunnerFactory; 123 private boolean m_delegateCommandSystemProperties = false; 124 125 protected Environment m_environment= new Environment(); 126 127 /** The suite runner name (defaults to TestNG.class.getName(). */ 128 protected String m_mainClass = TestNG.class.getName(); 129 130 /** True if the temporary file created by the Ant Task for command line parameters 131 * to TestNG should be preserved after execution. */ 132 protected boolean m_dump; 133 private boolean m_dumpEnv; 134 private boolean m_dumpSys; 135 136 protected boolean m_assertEnabled= true; 137 protected boolean m_haltOnFailure; 138 protected String m_onHaltTarget; 139 protected String m_failurePropertyName; 140 protected boolean m_haltOnSkipped; 141 protected String m_skippedPropertyName; 142 protected boolean m_haltOnFSP; 143 protected String m_fspPropertyName; 144 protected String m_includedGroups; 145 protected String m_excludedGroups; 146 protected String m_parallelMode; 147 protected String m_threadCount; 148 protected String m_dataproviderthreadCount; 149 protected String m_configFailurePolicy; 150 protected Boolean m_randomizeSuites; 151 public String m_useDefaultListeners; 152 private String m_suiteName="Ant suite"; 153 private String m_testName="Ant test"; 154 private Boolean m_skipFailedInvocationCounts; 155 private String m_methods; 156 private Mode mode = Mode.testng; 157 158 public enum Mode { 159 //lower-case to better look in build scripts 160 testng, junit, mixed; 161 } 162 163 /** 164 * The list of report listeners added via <reporter> sub-element of the Ant task 165 */ 166 private List<ReporterConfig> reporterConfigs = Lists.newArrayList(); 167 168 private String m_testNames = ""; 169 setParallel(String parallel)170 public void setParallel(String parallel) { 171 m_parallelMode= parallel; 172 } 173 setThreadCount(String threadCount)174 public void setThreadCount(String threadCount) { 175 m_threadCount= threadCount; 176 } 177 setDataProviderThreadCount(String dataproviderthreadCount)178 public void setDataProviderThreadCount(String dataproviderthreadCount) { 179 m_dataproviderthreadCount = dataproviderthreadCount; 180 } 181 setUseDefaultListeners(String f)182 public void setUseDefaultListeners(String f) { 183 m_useDefaultListeners= f; 184 } 185 186 // Ant task settings setHaltonfailure(boolean value)187 public void setHaltonfailure(boolean value) { 188 m_haltOnFailure= value; 189 } 190 setOnHaltTarget(String targetName)191 public void setOnHaltTarget(String targetName) { 192 m_onHaltTarget= targetName; 193 } 194 setFailureProperty(String propertyName)195 public void setFailureProperty(String propertyName) { 196 m_failurePropertyName= propertyName; 197 } 198 setHaltonskipped(boolean value)199 public void setHaltonskipped(boolean value) { 200 m_haltOnSkipped= value; 201 } 202 setSkippedProperty(String propertyName)203 public void setSkippedProperty(String propertyName) { 204 m_skippedPropertyName= propertyName; 205 } 206 setHaltonFSP(boolean value)207 public void setHaltonFSP(boolean value) { 208 m_haltOnFSP= value; 209 } 210 setFSPProperty(String propertyName)211 public void setFSPProperty(String propertyName) { 212 m_fspPropertyName= propertyName; 213 } 214 setDelegateCommandSystemProperties(boolean value)215 public void setDelegateCommandSystemProperties(boolean value){ 216 m_delegateCommandSystemProperties = value; 217 } 218 219 /** 220 * Sets the flag to log the command line. When verbose is set to true 221 * the command line parameters are stored in a temporary file stored 222 * in the user's default temporary file directory. The file created is 223 * prefixed with "testng". 224 */ setDumpCommand(boolean verbose)225 public void setDumpCommand(boolean verbose) { 226 m_dump = verbose; 227 } 228 229 /** 230 * Sets the flag to write on <code>System.out</code> the Ant 231 * Environment properties. 232 * 233 * @param verbose <tt>true</tt> for printing 234 */ setDumpEnv(boolean verbose)235 public void setDumpEnv(boolean verbose) { 236 m_dumpEnv= verbose; 237 } 238 239 /** 240 * Sets te flag to write on <code>System.out</code> the system properties. 241 * @param verbose <tt>true</tt> for dumping the info 242 */ setDumpSys(boolean verbose)243 public void setDumpSys(boolean verbose) { 244 m_dumpSys= verbose; 245 } 246 setEnableAssert(boolean flag)247 public void setEnableAssert(boolean flag) { 248 m_assertEnabled= flag; 249 } 250 251 /** 252 * The directory to invoke the VM in. 253 * @param workingDir the directory to invoke the JVM from. 254 */ setWorkingDir(File workingDir)255 public void setWorkingDir(File workingDir) { 256 m_workingDir= workingDir; 257 } 258 259 /** 260 * Sets a particular JVM to be used. Default is 'java' and is solved 261 * by <code>Runtime.exec()</code>. 262 * 263 * @param jvm the new jvm 264 */ setJvm(String jvm)265 public void setJvm(String jvm) { 266 getJavaCommand().setVm(jvm); 267 } 268 269 /** 270 * Set the timeout value (in milliseconds). 271 * 272 * <p>If the tests are running for more than this value, the tests 273 * will be canceled. 274 * 275 * </p> 276 * @param value the maximum time (in milliseconds) allowed before declaring the test as 'timed-out' 277 */ setTimeout(Integer value)278 public void setTimeout(Integer value) { 279 m_timeout= value; 280 } 281 createJvmarg()282 public Commandline.Argument createJvmarg() { 283 return getJavaCommand().createVmArgument(); 284 } 285 addSysproperty(Environment.Variable sysp)286 public void addSysproperty(Environment.Variable sysp) { 287 getJavaCommand().addSysproperty(sysp); 288 } 289 290 /** 291 * Adds an environment variable; used when forking. 292 */ addEnv(Environment.Variable var)293 public void addEnv(Environment.Variable var) { 294 m_environment.addVariable(var); 295 } 296 297 /** 298 * Adds path to classpath used for tests. 299 * 300 * @return reference to the classpath in the embedded java command line 301 */ createClasspath()302 public Path createClasspath() { 303 return getJavaCommand().createClasspath(getProject()).createPath(); 304 } 305 306 /** 307 * Adds a path to the bootclasspath. 308 * @return reference to the bootclasspath in the embedded java command line 309 */ createBootclasspath()310 public Path createBootclasspath() { 311 return getJavaCommand().createBootclasspath(getProject()).createPath(); 312 } 313 314 /** 315 * Set the classpath to be used when running the Java class 316 * 317 * @param s an Ant Path object containing the classpath. 318 */ setClasspath(Path s)319 public void setClasspath(Path s) { 320 createClasspath().append(s); 321 } 322 323 /** 324 * Classpath to use, by reference. 325 * 326 * @param r a reference to an existing classpath 327 */ setClasspathRef(Reference r)328 public void setClasspathRef(Reference r) { 329 createClasspath().setRefid(r); 330 } 331 addXmlfileset(FileSet fs)332 public void addXmlfileset(FileSet fs) { 333 m_xmlFilesets.add(fs); 334 } 335 setXmlfilesetRef(Reference ref)336 public void setXmlfilesetRef(Reference ref) { 337 m_xmlFilesets.add(createResourceCollection(ref)); 338 } 339 addClassfileset(FileSet fs)340 public void addClassfileset(FileSet fs) { 341 m_classFilesets.add(appendClassSelector(fs)); 342 } 343 setClassfilesetRef(Reference ref)344 public void setClassfilesetRef(Reference ref) { 345 m_classFilesets.add(createResourceCollection(ref)); 346 } 347 setTestNames(String testNames)348 public void setTestNames(String testNames) { 349 m_testNames = testNames; 350 } 351 352 /** 353 * Sets the suite runner class to invoke 354 * @param s the name of the suite runner class 355 */ setSuiteRunnerClass(String s)356 public void setSuiteRunnerClass(String s) { 357 m_mainClass= s; 358 } 359 360 /** 361 * Sets the suite name 362 * @param s the name of the suite 363 */ setSuiteName(String s)364 public void setSuiteName(String s) { 365 m_suiteName= s; 366 } 367 368 /** 369 * Sets the test name 370 * @param s the name of the test 371 */ setTestName(String s)372 public void setTestName(String s) { 373 m_testName= s; 374 } 375 376 // TestNG settings setJUnit(boolean value)377 public void setJUnit(boolean value) { 378 mode = value ? Mode.junit : Mode.testng; 379 } 380 381 // TestNG settings setMode(Mode mode)382 public void setMode(Mode mode) { 383 this.mode = mode; 384 } 385 386 /** 387 * Sets the test output directory 388 * @param dir the name of directory 389 */ setOutputDir(File dir)390 public void setOutputDir(File dir) { 391 m_outputDir= dir; 392 } 393 394 /** 395 * Sets the test jar 396 * @param s the name of test jar 397 */ setTestJar(File s)398 public void setTestJar(File s) { 399 m_testjar= s; 400 } 401 setGroups(String groups)402 public void setGroups(String groups) { 403 m_includedGroups= groups; 404 } 405 setExcludedGroups(String groups)406 public void setExcludedGroups(String groups) { 407 m_excludedGroups= groups; 408 } 409 410 private Integer m_verbose= null; 411 412 private Integer m_suiteThreadPoolSize; 413 414 private String m_xmlPathInJar; 415 setVerbose(Integer verbose)416 public void setVerbose(Integer verbose) { 417 m_verbose= verbose; 418 } 419 setReporter(String listener)420 public void setReporter(String listener) { 421 m_listeners.add(listener); 422 } 423 setObjectFactory(String className)424 public void setObjectFactory(String className) { 425 m_objectFactory = className; 426 } 427 setTestRunnerFactory(String testRunnerFactory)428 public void setTestRunnerFactory(String testRunnerFactory) { 429 m_testRunnerFactory = testRunnerFactory; 430 } 431 setSuiteThreadPoolSize(Integer n)432 public void setSuiteThreadPoolSize(Integer n) { 433 m_suiteThreadPoolSize = n; 434 } 435 436 /** 437 * @deprecated Use "listeners" 438 */ 439 @Deprecated setListener(String listener)440 public void setListener(String listener) { 441 m_listeners.add(listener); 442 } 443 setListeners(String listeners)444 public void setListeners(String listeners) { 445 StringTokenizer st= new StringTokenizer(listeners, " ,"); 446 while(st.hasMoreTokens()) { 447 m_listeners.add(st.nextToken()); 448 } 449 } 450 setMethodSelectors(String methodSelectors)451 public void setMethodSelectors(String methodSelectors) { 452 StringTokenizer st= new StringTokenizer(methodSelectors, " ,"); 453 while(st.hasMoreTokens()) { 454 m_methodselectors.add(st.nextToken()); 455 } 456 } 457 setConfigFailurePolicy(String failurePolicy)458 public void setConfigFailurePolicy(String failurePolicy) { 459 m_configFailurePolicy = failurePolicy; 460 } 461 setRandomizeSuites(Boolean randomizeSuites)462 public void setRandomizeSuites(Boolean randomizeSuites) { 463 m_randomizeSuites = randomizeSuites; 464 } 465 setMethods(String methods)466 public void setMethods(String methods) { 467 m_methods = methods; 468 } 469 470 /** 471 * Launches TestNG in a new JVM. 472 * 473 * {@inheritDoc} 474 */ 475 @Override execute()476 public void execute() throws BuildException { 477 validateOptions(); 478 479 CommandlineJava cmd = getJavaCommand(); 480 cmd.setClassname(m_mainClass); 481 if(m_assertEnabled) { 482 cmd.createVmArgument().setValue("-ea"); 483 } 484 if (m_delegateCommandSystemProperties) { 485 delegateCommandSystemProperties(); 486 } 487 List<String> argv = createArguments(); 488 489 String fileName= ""; 490 FileWriter fw= null; 491 BufferedWriter bw= null; 492 try { 493 File f= File.createTempFile("testng", ""); 494 fileName= f.getAbsolutePath(); 495 496 // If the user asked to see the command, preserve the file 497 if(!m_dump) { 498 f.deleteOnExit(); 499 } 500 fw= new FileWriter(f); 501 bw= new BufferedWriter(fw); 502 for(String arg : argv) { 503 bw.write(arg); 504 bw.newLine(); 505 } 506 bw.flush(); 507 } 508 catch(IOException e) { 509 e.printStackTrace(); 510 } 511 finally { 512 try { 513 if(bw != null) { 514 bw.close(); 515 } 516 if(fw != null) { 517 fw.close(); 518 } 519 } 520 catch(IOException e) { 521 e.printStackTrace(); 522 } 523 } 524 525 printDebugInfo(fileName); 526 527 createClasspath().setLocation(findJar()); 528 529 cmd.createArgument().setValue("@" + fileName); 530 531 ExecuteWatchdog watchdog= createWatchdog(); 532 boolean wasKilled= false; 533 int exitValue= executeAsForked(cmd, watchdog); 534 if(null != watchdog) { 535 wasKilled= watchdog.killedProcess(); 536 } 537 538 actOnResult(exitValue, wasKilled); 539 } 540 createArguments()541 private List<String> createArguments() { 542 List<String> argv= Lists.newArrayList(); 543 addBooleanIfTrue(argv, CommandLineArgs.JUNIT, mode == Mode.junit); 544 addBooleanIfTrue(argv, CommandLineArgs.MIXED, mode == Mode.mixed); 545 addBooleanIfTrue(argv, CommandLineArgs.SKIP_FAILED_INVOCATION_COUNTS, m_skipFailedInvocationCounts); 546 addIntegerIfNotNull(argv, CommandLineArgs.LOG, m_verbose); 547 addDefaultListeners(argv); 548 addOutputDir(argv); 549 addFileIfFile(argv, CommandLineArgs.TEST_JAR, m_testjar); 550 addStringIfNotBlank(argv, CommandLineArgs.GROUPS, m_includedGroups); 551 addStringIfNotBlank(argv, CommandLineArgs.EXCLUDED_GROUPS, m_excludedGroups); 552 addFilesOfRCollection(argv, CommandLineArgs.TEST_CLASS, m_classFilesets); 553 addListOfStringIfNotEmpty(argv, CommandLineArgs.LISTENER, m_listeners); 554 addListOfStringIfNotEmpty(argv, CommandLineArgs.METHOD_SELECTORS, m_methodselectors); 555 addStringIfNotNull(argv, CommandLineArgs.OBJECT_FACTORY, m_objectFactory); 556 addStringIfNotNull(argv, CommandLineArgs.TEST_RUNNER_FACTORY, m_testRunnerFactory); 557 addStringIfNotNull(argv, CommandLineArgs.PARALLEL, m_parallelMode); 558 addStringIfNotNull(argv, CommandLineArgs.CONFIG_FAILURE_POLICY, m_configFailurePolicy); 559 addBooleanIfTrue(argv, CommandLineArgs.RANDOMIZE_SUITES, m_randomizeSuites); 560 addStringIfNotNull(argv, CommandLineArgs.THREAD_COUNT, m_threadCount); 561 addStringIfNotNull(argv, CommandLineArgs.DATA_PROVIDER_THREAD_COUNT, m_dataproviderthreadCount); 562 addStringIfNotBlank(argv, CommandLineArgs.SUITE_NAME, m_suiteName); 563 addStringIfNotBlank(argv, CommandLineArgs.TEST_NAME, m_testName); 564 addStringIfNotBlank(argv, CommandLineArgs.TEST_NAMES, m_testNames); 565 addStringIfNotBlank(argv, CommandLineArgs.METHODS, m_methods); 566 addReporterConfigs(argv); 567 addIntegerIfNotNull(argv, CommandLineArgs.SUITE_THREAD_POOL_SIZE, m_suiteThreadPoolSize); 568 addStringIfNotNull(argv, CommandLineArgs.XML_PATH_IN_JAR, m_xmlPathInJar); 569 addXmlFiles(argv); 570 return argv; 571 } 572 addDefaultListeners(List<String> argv)573 private void addDefaultListeners(List<String> argv) { 574 if (m_useDefaultListeners != null) { 575 String useDefaultListeners = "false"; 576 if ("yes".equalsIgnoreCase(m_useDefaultListeners) || "true".equalsIgnoreCase(m_useDefaultListeners)) { 577 useDefaultListeners = "true"; 578 } 579 argv.add(CommandLineArgs.USE_DEFAULT_LISTENERS); 580 argv.add(useDefaultListeners); 581 } 582 } 583 addOutputDir(List<String> argv)584 private void addOutputDir(List<String> argv) { 585 if (null != m_outputDir) { 586 if (!m_outputDir.exists()) { 587 m_outputDir.mkdirs(); 588 } 589 if (m_outputDir.isDirectory()) { 590 argv.add(CommandLineArgs.OUTPUT_DIRECTORY); 591 argv.add(m_outputDir.getAbsolutePath()); 592 } else { 593 throw new BuildException("Output directory is not a directory: " + m_outputDir); 594 } 595 } 596 } 597 addReporterConfigs(List<String> argv)598 private void addReporterConfigs(List<String> argv) { 599 for (ReporterConfig reporterConfig : reporterConfigs) { 600 argv.add(CommandLineArgs.REPORTER); 601 argv.add(reporterConfig.serialize()); 602 } 603 } 604 addFilesOfRCollection(List<String> argv, String name, List<ResourceCollection> resources)605 private void addFilesOfRCollection(List<String> argv, String name, List<ResourceCollection> resources) { 606 addArgumentsIfNotEmpty(argv, name, getFiles(resources), ","); 607 } 608 addListOfStringIfNotEmpty(List<String> argv, String name, List<String> arguments)609 private void addListOfStringIfNotEmpty(List<String> argv, String name, List<String> arguments) { 610 addArgumentsIfNotEmpty(argv, name, arguments, ";"); 611 } 612 addArgumentsIfNotEmpty(List<String> argv, String name, List<String> arguments, String separator)613 private void addArgumentsIfNotEmpty(List<String> argv, String name, List<String> arguments, String separator) { 614 if (arguments != null && !arguments.isEmpty()) { 615 argv.add(name); 616 String value= Utils.join(arguments, separator); 617 argv.add(value); 618 } 619 } 620 addFileIfFile(List<String> argv, String name, File file)621 private void addFileIfFile(List<String> argv, String name, File file) { 622 if ((null != file) && file.isFile()) { 623 argv.add(name); 624 argv.add(file.getAbsolutePath()); 625 } 626 } 627 addBooleanIfTrue(List<String> argv, String name, Boolean value)628 private void addBooleanIfTrue(List<String> argv, String name, Boolean value) { 629 if (TRUE.equals(value)) { 630 argv.add(name); 631 } 632 } 633 addIntegerIfNotNull(List<String> argv, String name, Integer value)634 private void addIntegerIfNotNull(List<String> argv, String name, Integer value) { 635 if (value != null) { 636 argv.add(name); 637 argv.add(value.toString()); 638 } 639 } 640 addStringIfNotNull(List<String> argv, String name, String value)641 private void addStringIfNotNull(List<String> argv, String name, String value) { 642 if (value != null) { 643 argv.add(name); 644 argv.add(value); 645 } 646 } 647 addStringIfNotBlank(List<String> argv, String name, String value)648 private void addStringIfNotBlank(List<String> argv, String name, String value) { 649 if (isStringNotBlank(value)) { 650 argv.add(name); 651 argv.add(value); 652 } 653 } 654 addXmlFiles(List<String> argv)655 private void addXmlFiles(List<String> argv) { 656 for (String file : getSuiteFileNames()) { 657 argv.add(file); 658 } 659 } 660 661 /** 662 * @return the list of the XML file names. This method can be overridden by subclasses. 663 */ getSuiteFileNames()664 protected List<String> getSuiteFileNames() { 665 List<String> result = Lists.newArrayList(); 666 667 for(String file : getFiles(m_xmlFilesets)) { 668 result.add(file); 669 } 670 671 return result; 672 } 673 delegateCommandSystemProperties()674 private void delegateCommandSystemProperties() { 675 // Iterate over command-line args and pass them through as sysproperty 676 // exclude any built-in properties that start with "ant." 677 for (Object propKey : getProject().getUserProperties().keySet()) { 678 String propName = (String) propKey; 679 String propVal = getProject().getUserProperty(propName); 680 if (propName.startsWith("ant.")) { 681 log("Excluding ant property: " + propName + ": " + propVal, Project.MSG_DEBUG); 682 } else { 683 log("Including user property: " + propName + ": " + propVal, Project.MSG_DEBUG); 684 Environment.Variable var = new Environment.Variable(); 685 var.setKey(propName); 686 var.setValue(propVal); 687 addSysproperty(var); 688 } 689 } 690 } 691 printDebugInfo(String fileName)692 private void printDebugInfo(String fileName) { 693 if(m_dumpSys) { 694 System.out.println("* SYSTEM PROPERTIES *"); 695 Properties props= System.getProperties(); 696 Enumeration en= props.propertyNames(); 697 while(en.hasMoreElements()) { 698 String key= (String) en.nextElement(); 699 System.out.println(key + ": " + props.getProperty(key)); 700 } 701 System.out.println(""); 702 } 703 if(m_dumpEnv) { 704 String[] vars= m_environment.getVariables(); 705 if(null != vars && vars.length > 0) { 706 System.out.println("* ENVIRONMENT *"); 707 for(String v: vars) { 708 System.out.println(v); 709 } 710 System.out.println(""); 711 } 712 } 713 if(m_dump) { 714 dumpCommand(fileName); 715 } 716 } 717 ppp(String string)718 private void ppp(String string) { 719 System.out.println("[TestNGAntTask] " + string); 720 } 721 actOnResult(int exitValue, boolean wasKilled)722 protected void actOnResult(int exitValue, boolean wasKilled) { 723 if(exitValue == -1) { 724 executeHaltTarget(exitValue); 725 throw new BuildException("an error occured when running TestNG tests"); 726 } 727 728 if((exitValue & TestNG.HAS_NO_TEST) == TestNG.HAS_NO_TEST) { 729 if(m_haltOnFailure) { 730 executeHaltTarget(exitValue); 731 throw new BuildException("No tests were run"); 732 } 733 else { 734 if(null != m_failurePropertyName) { 735 getProject().setNewProperty(m_failurePropertyName, "true"); 736 } 737 738 log("TestNG haven't found any tests to be run", Project.MSG_DEBUG); 739 } 740 } 741 742 boolean failed= ((exitValue & TestNG.HAS_FAILURE) == TestNG.HAS_FAILURE) || wasKilled; 743 if(failed) { 744 final String msg= wasKilled ? "The tests timed out and were killed." : "The tests failed."; 745 if(m_haltOnFailure) { 746 executeHaltTarget(exitValue); 747 throw new BuildException(msg); 748 } 749 else { 750 if(null != m_failurePropertyName) { 751 getProject().setNewProperty(m_failurePropertyName, "true"); 752 } 753 754 log(msg, Project.MSG_INFO); 755 } 756 } 757 758 if((exitValue & TestNG.HAS_SKIPPED) == TestNG.HAS_SKIPPED) { 759 if(m_haltOnSkipped) { 760 executeHaltTarget(exitValue); 761 throw new BuildException("There are TestNG SKIPPED tests"); 762 } 763 else { 764 if(null != m_skippedPropertyName) { 765 getProject().setNewProperty(m_skippedPropertyName, "true"); 766 } 767 768 log("There are TestNG SKIPPED tests", Project.MSG_DEBUG); 769 } 770 } 771 772 if((exitValue & TestNG.HAS_FSP) == TestNG.HAS_FSP) { 773 if(m_haltOnFSP) { 774 executeHaltTarget(exitValue); 775 throw new BuildException("There are TestNG FAILED WITHIN SUCCESS PERCENTAGE tests"); 776 } 777 else { 778 if(null != m_fspPropertyName) { 779 getProject().setNewProperty(m_fspPropertyName, "true"); 780 } 781 782 log("There are TestNG FAILED WITHIN SUCCESS PERCENTAGE tests", Project.MSG_DEBUG); 783 } 784 } 785 } 786 787 /** Executes the target, if any, that user designates executing before failing the test */ executeHaltTarget(int exitValue)788 private void executeHaltTarget(int exitValue) { 789 if(m_onHaltTarget != null) { 790 if(m_outputDir != null) { 791 getProject().setProperty("testng.outputdir", m_outputDir.getAbsolutePath()); 792 } 793 getProject().setProperty("testng.returncode", String.valueOf(exitValue)); 794 Target t= (Target) getProject().getTargets().get(m_onHaltTarget); 795 if(t != null) { 796 t.execute(); 797 } 798 } 799 } 800 801 /** 802 * Executes the command line as a new process. 803 * 804 * @param cmd the command to execute 805 * @param watchdog 806 * @return the exit status of the subprocess or INVALID. 807 */ executeAsForked(CommandlineJava cmd, ExecuteWatchdog watchdog)808 protected int executeAsForked(CommandlineJava cmd, ExecuteWatchdog watchdog) { 809 Execute execute= new Execute(new TestNGLogSH(this, Project.MSG_INFO, Project.MSG_WARN, (m_verbose == null || m_verbose < 5)), 810 watchdog); 811 execute.setCommandline(cmd.getCommandline()); 812 execute.setAntRun(getProject()); 813 if(m_workingDir != null) { 814 if(m_workingDir.exists() && m_workingDir.isDirectory()) { 815 execute.setWorkingDirectory(m_workingDir); 816 } 817 else { 818 log("Ignoring invalid working directory : " + m_workingDir, Project.MSG_WARN); 819 } 820 } 821 822 String[] environment= m_environment.getVariables(); 823 if(null != environment) { 824 for(String envEntry : environment) { 825 log("Setting environment variable: " + envEntry, Project.MSG_VERBOSE); 826 } 827 } 828 829 execute.setEnvironment(environment); 830 831 log(cmd.describeCommand(), Project.MSG_VERBOSE); 832 int retVal; 833 try { 834 retVal= execute.execute(); 835 } 836 catch(IOException e) { 837 throw new BuildException("Process fork failed.", e, getLocation()); 838 } 839 840 return retVal; 841 } 842 843 /** 844 * Creates or returns the already created <CODE>CommandlineJava</CODE>. 845 */ getJavaCommand()846 protected CommandlineJava getJavaCommand() { 847 if(null == m_javaCommand) { 848 m_javaCommand = new CommandlineJava(); 849 } 850 851 return m_javaCommand; 852 } 853 854 /** 855 * @return <tt>null</tt> if there is no timeout value, otherwise the 856 * watchdog instance. 857 * 858 * @throws BuildException under unspecified circumstances 859 * @since Ant 1.2 860 */ createWatchdog()861 protected ExecuteWatchdog createWatchdog() /*throws BuildException*/ { 862 if(m_timeout == null) { 863 return null; 864 } 865 866 return new ExecuteWatchdog(m_timeout.longValue()); 867 } 868 validateOptions()869 protected void validateOptions() throws BuildException { 870 int suiteCount = getSuiteFileNames().size(); 871 if (suiteCount == 0 872 && m_classFilesets.size() == 0 873 && Utils.isStringEmpty(m_methods) 874 && ((null == m_testjar) || !m_testjar.isFile())) { 875 throw new BuildException("No suites, classes, methods or jar file was specified."); 876 } 877 878 if((null != m_includedGroups) && (m_classFilesets.size() == 0 && suiteCount == 0)) { 879 throw new BuildException("No class filesets or xml file sets specified while using groups"); 880 } 881 882 if(m_onHaltTarget != null) { 883 if(!getProject().getTargets().containsKey(m_onHaltTarget)) { 884 throw new BuildException("Target " + m_onHaltTarget + " not found in this project"); 885 } 886 } 887 888 } 889 createResourceCollection(Reference ref)890 private ResourceCollection createResourceCollection(Reference ref) { 891 Object o = ref.getReferencedObject(); 892 if (!(o instanceof ResourceCollection)) { 893 throw new BuildException("Only File based ResourceCollections are supported."); 894 } 895 ResourceCollection rc = (ResourceCollection) o; 896 if (!rc.isFilesystemOnly()) { 897 throw new BuildException("Only ResourceCollections from local file system are supported."); 898 } 899 return rc; 900 } 901 appendClassSelector(FileSet fs)902 private FileSet appendClassSelector(FileSet fs) { 903 FilenameSelector selector= new FilenameSelector(); 904 selector.setName("**/*.class"); 905 selector.setProject(getProject()); 906 fs.appendSelector(selector); 907 908 return fs; 909 } 910 findJar()911 private File findJar() { 912 Class thisClass= getClass(); 913 String resource= thisClass.getName().replace('.', '/') + ".class"; 914 URL url= thisClass.getClassLoader().getResource(resource); 915 916 if(null != url) { 917 String u= url.toString(); 918 if(u.startsWith("jar:file:")) { 919 int pling= u.indexOf("!"); 920 String jarName= u.substring(4, pling); 921 922 return new File(fromURI(jarName)); 923 } 924 else if(u.startsWith("file:")) { 925 int tail= u.indexOf(resource); 926 String dirName= u.substring(0, tail); 927 928 return new File(fromURI(dirName)); 929 } 930 } 931 932 return null; 933 } 934 fromURI(String uri)935 private String fromURI(String uri) { 936 URL url= null; 937 try { 938 url= new URL(uri); 939 } 940 catch(MalformedURLException murle) { 941 } 942 if((null == url) || !("file".equals(url.getProtocol()))) { 943 throw new IllegalArgumentException("Can only handle valid file: URIs"); 944 } 945 946 StringBuffer buf= new StringBuffer(url.getHost()); 947 if(buf.length() > 0) { 948 buf.insert(0, File.separatorChar).insert(0, File.separatorChar); 949 } 950 951 String file= url.getFile(); 952 int queryPos= file.indexOf('?'); 953 buf.append((queryPos < 0) ? file : file.substring(0, queryPos)); 954 955 uri= buf.toString().replace('/', File.separatorChar); 956 957 if((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) 958 && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) { 959 uri= uri.substring(1); 960 } 961 962 StringBuffer sb= new StringBuffer(); 963 CharacterIterator iter= new StringCharacterIterator(uri); 964 for(char c= iter.first(); c != CharacterIterator.DONE; c= iter.next()) { 965 if(c == '%') { 966 char c1= iter.next(); 967 if(c1 != CharacterIterator.DONE) { 968 int i1= Character.digit(c1, 16); 969 char c2= iter.next(); 970 if(c2 != CharacterIterator.DONE) { 971 int i2= Character.digit(c2, 16); 972 sb.append((char) ((i1 << 4) + i2)); 973 } 974 } 975 } 976 else { 977 sb.append(c); 978 } 979 } 980 981 return sb.toString(); 982 } 983 984 /** 985 * Returns the list of files corresponding to the resource collection 986 * 987 * @param resources 988 * @return the list of files corresponding to the resource collection 989 * @throws BuildException 990 */ getFiles(List<ResourceCollection> resources)991 private List<String> getFiles(List<ResourceCollection> resources) throws BuildException { 992 List<String> files= Lists.newArrayList(); 993 for (ResourceCollection rc : resources) { 994 for (Iterator i = rc.iterator(); i.hasNext();) { 995 Object o = i.next(); 996 if (o instanceof FileResource) { 997 FileResource fr = ((FileResource) o); 998 if (fr.isDirectory()) { 999 throw new BuildException("Directory based FileResources are not supported."); 1000 } 1001 if (!fr.isExists()) { 1002 log("'" + fr.toLongString() + "' does not exist", Project.MSG_VERBOSE); 1003 } 1004 files.add(fr.getFile().getAbsolutePath()); 1005 } else { 1006 log("Unsupported Resource type: " + o.toString(), Project.MSG_VERBOSE); 1007 } 1008 } 1009 } 1010 return files; 1011 } 1012 1013 /** 1014 * Returns the list of files corresponding to the fileset 1015 * 1016 * @param filesets 1017 * @return the list of files corresponding to the fileset 1018 * @throws BuildException 1019 */ fileset(FileSet fileset)1020 private List<String> fileset(FileSet fileset) throws BuildException { 1021 List<String> files= Lists.newArrayList(); 1022 1023 DirectoryScanner ds= fileset.getDirectoryScanner(getProject()); 1024 1025 for(String file : ds.getIncludedFiles()) { 1026 files.add(ds.getBasedir() + File.separator + file); 1027 } 1028 1029 return files; 1030 } 1031 1032 /** 1033 * Adds double quotes to the command line argument if it contains spaces. 1034 * @param pCommandLineArg the command line argument 1035 * @return pCommandLineArg in double quotes if it contains space. 1036 * 1037 */ doubleQuote(String pCommandLineArg)1038 private static String doubleQuote(String pCommandLineArg) { 1039 if(pCommandLineArg.indexOf(" ") != -1 && !(pCommandLineArg.startsWith("\"") && pCommandLineArg.endsWith("\""))) { 1040 return "\"" + pCommandLineArg + '\"'; 1041 } 1042 1043 return pCommandLineArg; 1044 } 1045 1046 /** 1047 * Creates a string representation of the path. 1048 */ createPathString(Path path, String sep)1049 private String createPathString(Path path, String sep) { 1050 if(path == null) { 1051 return null; 1052 } 1053 1054 final StringBuffer buf= new StringBuffer(); 1055 1056 for(int i= 0; i < path.list().length; i++) { 1057 File file= getProject().resolveFile(path.list()[i]); 1058 1059 if(!file.exists()) { 1060 log("Classpath entry not found: " + file, Project.MSG_WARN); 1061 } 1062 1063 buf.append(file.getAbsolutePath()).append(sep); 1064 } 1065 1066 if(path.list().length > 0) { // cut the last ; 1067 buf.deleteCharAt(buf.length() - 1); 1068 } 1069 1070 return buf.toString(); 1071 } 1072 dumpCommand(String fileName)1073 private void dumpCommand(String fileName) { 1074 ppp("TESTNG PASSED @" + fileName + " WHICH CONTAINS:"); 1075 readAndPrintFile(fileName); 1076 } 1077 readAndPrintFile(String fileName)1078 private void readAndPrintFile(String fileName) { 1079 File file = new File(fileName); 1080 BufferedReader br = null; 1081 try { 1082 br = new BufferedReader(new FileReader(file)); 1083 String line = br.readLine(); 1084 while (line != null) { 1085 System.out.println(" " + line); 1086 line = br.readLine(); 1087 } 1088 } 1089 catch(IOException ex) { 1090 ex.printStackTrace(); 1091 } finally { 1092 if (br != null) { 1093 try { 1094 br.close(); 1095 } catch (IOException e) { 1096 e.printStackTrace(); 1097 } 1098 } 1099 } 1100 } 1101 addConfiguredReporter(ReporterConfig reporterConfig)1102 public void addConfiguredReporter(ReporterConfig reporterConfig) { 1103 reporterConfigs.add(reporterConfig); 1104 } 1105 setSkipFailedInvocationCounts(boolean skip)1106 public void setSkipFailedInvocationCounts(boolean skip) { 1107 m_skipFailedInvocationCounts = skip; 1108 } 1109 setXmlPathInJar(String path)1110 public void setXmlPathInJar(String path) { 1111 m_xmlPathInJar = path; 1112 } 1113 /** 1114 * Add the referenced property set as system properties for the TestNG JVM. 1115 * 1116 * @param sysPropertySet A PropertySet of system properties. 1117 */ addConfiguredPropertySet(PropertySet sysPropertySet)1118 public void addConfiguredPropertySet(PropertySet sysPropertySet) { 1119 Properties properties = sysPropertySet.getProperties(); 1120 log(properties.keySet().size() + " properties found in nested propertyset", Project.MSG_VERBOSE); 1121 for (Object propKeyObj : properties.keySet()) { 1122 String propKey = (String) propKeyObj; 1123 Environment.Variable sysProp = new Environment.Variable(); 1124 sysProp.setKey(propKey); 1125 if (properties.get(propKey) instanceof String) { 1126 String propVal = (String) properties.get(propKey); 1127 sysProp.setValue(propVal); 1128 getJavaCommand().addSysproperty(sysProp); 1129 log("Added system property " + propKey + " with value " + propVal, Project.MSG_VERBOSE); 1130 } else { 1131 log("Ignoring non-String property " + propKey, Project.MSG_WARN); 1132 } 1133 } 1134 } 1135 1136 @Override handleOutput(String output)1137 protected void handleOutput(String output) { 1138 if (output.startsWith(VerboseReporter.LISTENER_PREFIX)) { 1139 //send everything from VerboseReporter to verbose level unless log level is > 4 1140 log(output, m_verbose < 5 ? Project.MSG_VERBOSE : Project.MSG_INFO); 1141 } else { 1142 super.handleOutput(output); 1143 } 1144 } 1145 1146 private static class TestNGLogOS extends LogOutputStream { 1147 1148 private Task task; 1149 private boolean verbose; 1150 TestNGLogOS(Task task, int level, boolean verbose)1151 public TestNGLogOS(Task task, int level, boolean verbose) { 1152 super(task, level); 1153 this.task = task; 1154 this.verbose = verbose; 1155 } 1156 1157 @Override processLine(String line, int level)1158 protected void processLine(String line, int level) { 1159 if (line.startsWith(VerboseReporter.LISTENER_PREFIX)) { 1160 task.log(line, verbose ? Project.MSG_VERBOSE : Project.MSG_INFO); 1161 } else { 1162 super.processLine(line, level); 1163 } 1164 } 1165 } 1166 1167 protected static class TestNGLogSH extends PumpStreamHandler { 1168 TestNGLogSH(Task task, int outlevel, int errlevel, boolean verbose)1169 public TestNGLogSH(Task task, int outlevel, int errlevel, boolean verbose) { 1170 super(new TestNGLogOS(task, outlevel, verbose), 1171 new LogOutputStream(task, errlevel)); 1172 } 1173 } 1174 } 1175