1. /*
  2. * Copyright 2000-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.optional.junit;
  18. import java.io.BufferedWriter;
  19. import java.io.File;
  20. import java.io.FileOutputStream;
  21. import java.io.FileWriter;
  22. import java.io.IOException;
  23. import java.io.OutputStream;
  24. import java.io.PrintWriter;
  25. import java.util.ArrayList;
  26. import java.util.Collection;
  27. import java.util.Enumeration;
  28. import java.util.HashMap;
  29. import java.util.Hashtable;
  30. import java.util.Iterator;
  31. import java.util.List;
  32. import java.util.Map;
  33. import java.util.Properties;
  34. import java.util.Vector;
  35. import org.apache.tools.ant.AntClassLoader;
  36. import org.apache.tools.ant.BuildException;
  37. import org.apache.tools.ant.Project;
  38. import org.apache.tools.ant.Task;
  39. import org.apache.tools.ant.taskdefs.Execute;
  40. import org.apache.tools.ant.taskdefs.ExecuteWatchdog;
  41. import org.apache.tools.ant.taskdefs.LogOutputStream;
  42. import org.apache.tools.ant.taskdefs.LogStreamHandler;
  43. import org.apache.tools.ant.types.Assertions;
  44. import org.apache.tools.ant.types.Commandline;
  45. import org.apache.tools.ant.types.CommandlineJava;
  46. import org.apache.tools.ant.types.EnumeratedAttribute;
  47. import org.apache.tools.ant.types.Environment;
  48. import org.apache.tools.ant.types.Path;
  49. import org.apache.tools.ant.types.Permissions;
  50. import org.apache.tools.ant.types.PropertySet;
  51. import org.apache.tools.ant.util.FileUtils;
  52. import org.apache.tools.ant.util.LoaderUtils;
  53. import junit.framework.AssertionFailedError;
  54. import junit.framework.Test;
  55. import junit.framework.TestResult;
  56. /**
  57. * Runs JUnit tests.
  58. *
  59. * <p> JUnit is a framework to create unit test. It has been initially
  60. * created by Erich Gamma and Kent Beck. JUnit can be found at <a
  61. * href="http://www.junit.org">http://www.junit.org</a>.
  62. *
  63. * <p> <code>JUnitTask</code> can run a single specific
  64. * <code>JUnitTest</code> using the <code>test</code> element.</p>
  65. * For example, the following target <code><pre>
  66. * <target name="test-int-chars" depends="jar-test">
  67. * <echo message="testing international characters"/>
  68. * <junit printsummary="no" haltonfailure="yes" fork="false">
  69. * <classpath refid="classpath"/>
  70. * <formatter type="plain" usefile="false" />
  71. * <test name="org.apache.ecs.InternationalCharTest" />
  72. * </junit>
  73. * </target>
  74. * </pre></code>
  75. * <p>runs a single junit test
  76. * (<code>org.apache.ecs.InternationalCharTest</code>) in the current
  77. * VM using the path with id <code>classpath</code> as classpath and
  78. * presents the results formatted using the standard
  79. * <code>plain</code> formatter on the command line.</p>
  80. *
  81. * <p> This task can also run batches of tests. The
  82. * <code>batchtest</code> element creates a <code>BatchTest</code>
  83. * based on a fileset. This allows, for example, all classes found in
  84. * directory to be run as testcases.</p>
  85. *
  86. * <p>For example,</p><code><pre>
  87. * <target name="run-tests" depends="dump-info,compile-tests" if="junit.present">
  88. * <junit printsummary="no" haltonfailure="yes" fork="${junit.fork}">
  89. * <jvmarg value="-classic"/>
  90. * <classpath refid="tests-classpath"/>
  91. * <sysproperty key="build.tests" value="${build.tests}"/>
  92. * <formatter type="brief" usefile="false" />
  93. * <batchtest>
  94. * <fileset dir="${tests.dir}">
  95. * <include name="**/*Test*" />
  96. * </fileset>
  97. * </batchtest>
  98. * </junit>
  99. * </target>
  100. * </pre></code>
  101. * <p>this target finds any classes with a <code>test</code> directory
  102. * anywhere in their path (under the top <code>${tests.dir}</code>, of
  103. * course) and creates <code>JUnitTest</code>'s for each one.</p>
  104. *
  105. * <p> Of course, <code><junit></code> and
  106. * <code><batch></code> elements can be combined for more
  107. * complex tests. For an example, see the ant <code>build.xml</code>
  108. * target <code>run-tests</code> (the second example is an edited
  109. * version).</p>
  110. *
  111. * <p> To spawn a new Java VM to prevent interferences between
  112. * different testcases, you need to enable <code>fork</code>. A
  113. * number of attributes and elements allow you to set up how this JVM
  114. * runs.
  115. *
  116. * @version $Revision: 1.83.2.12 $
  117. *
  118. * @since Ant 1.2
  119. *
  120. * @see JUnitTest
  121. * @see BatchTest
  122. */
  123. public class JUnitTask extends Task {
  124. private CommandlineJava commandline;
  125. private Vector tests = new Vector();
  126. private Vector batchTests = new Vector();
  127. private Vector formatters = new Vector();
  128. private File dir = null;
  129. private Integer timeout = null;
  130. private boolean summary = false;
  131. private boolean reloading = true;
  132. private String summaryValue = "";
  133. private JUnitTestRunner runner = null;
  134. private boolean newEnvironment = false;
  135. private Environment env = new Environment();
  136. private boolean includeAntRuntime = true;
  137. private Path antRuntimeClasses = null;
  138. private boolean showOutput = false;
  139. private File tmpDir;
  140. private AntClassLoader classLoader = null;
  141. private Permissions perm = null;
  142. private ForkMode forkMode = new ForkMode("perTest");
  143. private static final int STRING_BUFFER_SIZE = 128;
  144. /**
  145. * If true, force ant to re-classload all classes for each JUnit TestCase
  146. *
  147. * @param value force class reloading for each test case
  148. */
  149. public void setReloading(boolean value) {
  150. reloading = value;
  151. }
  152. /**
  153. * If true, smartly filter the stack frames of
  154. * JUnit errors and failures before reporting them.
  155. *
  156. * <p>This property is applied on all BatchTest (batchtest) and
  157. * JUnitTest (test) however it can possibly be overridden by their
  158. * own properties.</p>
  159. * @param value <tt>false</tt> if it should not filter, otherwise
  160. * <tt>true<tt>
  161. *
  162. * @since Ant 1.5
  163. */
  164. public void setFiltertrace(boolean value) {
  165. Enumeration e = allTests();
  166. while (e.hasMoreElements()) {
  167. BaseTest test = (BaseTest) e.nextElement();
  168. test.setFiltertrace(value);
  169. }
  170. }
  171. /**
  172. * If true, stop the build process when there is an error in a test.
  173. * This property is applied on all BatchTest (batchtest) and JUnitTest
  174. * (test) however it can possibly be overridden by their own
  175. * properties.
  176. * @param value <tt>true</tt> if it should halt, otherwise
  177. * <tt>false</tt>
  178. *
  179. * @since Ant 1.2
  180. */
  181. public void setHaltonerror(boolean value) {
  182. Enumeration e = allTests();
  183. while (e.hasMoreElements()) {
  184. BaseTest test = (BaseTest) e.nextElement();
  185. test.setHaltonerror(value);
  186. }
  187. }
  188. /**
  189. * Property to set to "true" if there is a error in a test.
  190. *
  191. * <p>This property is applied on all BatchTest (batchtest) and
  192. * JUnitTest (test), however, it can possibly be overriden by
  193. * their own properties.</p>
  194. * @param propertyName the name of the property to set in the
  195. * event of an error.
  196. *
  197. * @since Ant 1.4
  198. */
  199. public void setErrorProperty(String propertyName) {
  200. Enumeration e = allTests();
  201. while (e.hasMoreElements()) {
  202. BaseTest test = (BaseTest) e.nextElement();
  203. test.setErrorProperty(propertyName);
  204. }
  205. }
  206. /**
  207. * If true, stop the build process if a test fails
  208. * (errors are considered failures as well).
  209. * This property is applied on all BatchTest (batchtest) and
  210. * JUnitTest (test) however it can possibly be overridden by their
  211. * own properties.
  212. * @param value <tt>true</tt> if it should halt, otherwise
  213. * <tt>false</tt>
  214. *
  215. * @since Ant 1.2
  216. */
  217. public void setHaltonfailure(boolean value) {
  218. Enumeration e = allTests();
  219. while (e.hasMoreElements()) {
  220. BaseTest test = (BaseTest) e.nextElement();
  221. test.setHaltonfailure(value);
  222. }
  223. }
  224. /**
  225. * Property to set to "true" if there is a failure in a test.
  226. *
  227. * <p>This property is applied on all BatchTest (batchtest) and
  228. * JUnitTest (test), however, it can possibly be overriden by
  229. * their own properties.</p>
  230. * @param propertyName the name of the property to set in the
  231. * event of an failure.
  232. *
  233. * @since Ant 1.4
  234. */
  235. public void setFailureProperty(String propertyName) {
  236. Enumeration e = allTests();
  237. while (e.hasMoreElements()) {
  238. BaseTest test = (BaseTest) e.nextElement();
  239. test.setFailureProperty(propertyName);
  240. }
  241. }
  242. /**
  243. * If true, JVM should be forked for each test.
  244. *
  245. * <p>It avoids interference between testcases and possibly avoids
  246. * hanging the build. this property is applied on all BatchTest
  247. * (batchtest) and JUnitTest (test) however it can possibly be
  248. * overridden by their own properties.</p>
  249. * @param value <tt>true</tt> if a JVM should be forked, otherwise
  250. * <tt>false</tt>
  251. * @see #setTimeout
  252. *
  253. * @since Ant 1.2
  254. */
  255. public void setFork(boolean value) {
  256. Enumeration e = allTests();
  257. while (e.hasMoreElements()) {
  258. BaseTest test = (BaseTest) e.nextElement();
  259. test.setFork(value);
  260. }
  261. }
  262. /**
  263. * Set the behavior when {@link #setFork fork} fork has been enabled.
  264. *
  265. * <p>Possible values are "once", "perTest" and "perBatch". If
  266. * set to "once", only a single Java VM will be forked for all
  267. * tests, with "perTest" (the default) each test will run in a
  268. * fresh Java VM and "perBatch" will run all tests from the same
  269. * <batchtest> in the same Java VM.</p>
  270. *
  271. * <p>This attribute will be ignored if tests run in the same VM
  272. * as Ant.</p>
  273. *
  274. * <p>Only tests with the same configuration of haltonerror,
  275. * haltonfailure, errorproperty, failureproperty and filtertrace
  276. * can share a forked Java VM, so even if you set the value to
  277. * "once", Ant may need to fork mutliple VMs.</p>
  278. *
  279. * @since Ant 1.6.2
  280. */
  281. public void setForkMode(ForkMode mode) {
  282. this.forkMode = mode;
  283. }
  284. /**
  285. * If true, print one-line statistics for each test, or "withOutAndErr"
  286. * to also show standard output and error.
  287. *
  288. * Can take the values on, off, and withOutAndErr.
  289. * @param value <tt>true</tt> to print a summary,
  290. * <tt>withOutAndErr</tt> to include the test's output as
  291. * well, <tt>false</tt> otherwise.
  292. * @see SummaryJUnitResultFormatter
  293. *
  294. * @since Ant 1.2
  295. */
  296. public void setPrintsummary(SummaryAttribute value) {
  297. summaryValue = value.getValue();
  298. summary = value.asBoolean();
  299. }
  300. /**
  301. * Print summary enumeration values.
  302. */
  303. public static class SummaryAttribute extends EnumeratedAttribute {
  304. /**
  305. * list the possible values
  306. * @return array of allowed values
  307. */
  308. public String[] getValues() {
  309. return new String[] {"true", "yes", "false", "no",
  310. "on", "off", "withOutAndErr"};
  311. }
  312. /**
  313. * gives the boolean equivalent of the authorized values
  314. * @return boolean equivalent of the value
  315. */
  316. public boolean asBoolean() {
  317. String value = getValue();
  318. return "true".equals(value)
  319. || "on".equals(value)
  320. || "yes".equals(value)
  321. || "withOutAndErr".equals(value);
  322. }
  323. }
  324. /**
  325. * Set the timeout value (in milliseconds).
  326. *
  327. * <p>If the test is running for more than this value, the test
  328. * will be canceled. (works only when in 'fork' mode).</p>
  329. * @param value the maximum time (in milliseconds) allowed before
  330. * declaring the test as 'timed-out'
  331. * @see #setFork(boolean)
  332. *
  333. * @since Ant 1.2
  334. */
  335. public void setTimeout(Integer value) {
  336. timeout = value;
  337. }
  338. /**
  339. * Set the maximum memory to be used by all forked JVMs.
  340. * @param max the value as defined by <tt>-mx</tt> or <tt>-Xmx</tt>
  341. * in the java command line options.
  342. *
  343. * @since Ant 1.2
  344. */
  345. public void setMaxmemory(String max) {
  346. getCommandline().setMaxmemory(max);
  347. }
  348. /**
  349. * The command used to invoke the Java Virtual Machine,
  350. * default is 'java'. The command is resolved by
  351. * java.lang.Runtime.exec(). Ignored if fork is disabled.
  352. *
  353. * @param value the new VM to use instead of <tt>java</tt>
  354. * @see #setFork(boolean)
  355. *
  356. * @since Ant 1.2
  357. */
  358. public void setJvm(String value) {
  359. getCommandline().setVm(value);
  360. }
  361. /**
  362. * Adds a JVM argument; ignored if not forking.
  363. *
  364. * @return create a new JVM argument so that any argument can be
  365. * passed to the JVM.
  366. * @see #setFork(boolean)
  367. *
  368. * @since Ant 1.2
  369. */
  370. public Commandline.Argument createJvmarg() {
  371. return getCommandline().createVmArgument();
  372. }
  373. /**
  374. * The directory to invoke the VM in. Ignored if no JVM is forked.
  375. * @param dir the directory to invoke the JVM from.
  376. * @see #setFork(boolean)
  377. *
  378. * @since Ant 1.2
  379. */
  380. public void setDir(File dir) {
  381. this.dir = dir;
  382. }
  383. /**
  384. * Adds a system property that tests can access.
  385. * This might be useful to tranfer Ant properties to the
  386. * testcases when JVM forking is not enabled.
  387. *
  388. * @since Ant 1.3
  389. * @deprecated since ant 1.6
  390. * @param sysp environment variable to add
  391. */
  392. public void addSysproperty(Environment.Variable sysp) {
  393. getCommandline().addSysproperty(sysp);
  394. }
  395. /**
  396. * Adds a system property that tests can access.
  397. * This might be useful to tranfer Ant properties to the
  398. * testcases when JVM forking is not enabled.
  399. * @param sysp new environment variable to add
  400. * @since Ant 1.6
  401. */
  402. public void addConfiguredSysproperty(Environment.Variable sysp) {
  403. // get a build exception if there is a missing key or value
  404. // see bugzilla report 21684
  405. String testString = sysp.getContent();
  406. getProject().log("sysproperty added : " + testString, Project.MSG_DEBUG);
  407. getCommandline().addSysproperty(sysp);
  408. }
  409. /**
  410. * Adds a set of properties that will be used as system properties
  411. * that tests can access.
  412. *
  413. * This might be useful to tranfer Ant properties to the
  414. * testcases when JVM forking is not enabled.
  415. *
  416. * @param sysp set of properties to be added
  417. * @since Ant 1.6
  418. */
  419. public void addSyspropertyset(PropertySet sysp) {
  420. getCommandline().addSyspropertyset(sysp);
  421. }
  422. /**
  423. * Adds path to classpath used for tests.
  424. *
  425. * @return reference to the classpath in the embedded java command line
  426. * @since Ant 1.2
  427. */
  428. public Path createClasspath() {
  429. return getCommandline().createClasspath(getProject()).createPath();
  430. }
  431. /**
  432. * Adds a path to the bootclasspath.
  433. * @return reference to the bootclasspath in the embedded java command line
  434. * @since Ant 1.6
  435. */
  436. public Path createBootclasspath() {
  437. return getCommandline().createBootclasspath(getProject()).createPath();
  438. }
  439. /**
  440. * Adds an environment variable; used when forking.
  441. *
  442. * <p>Will be ignored if we are not forking a new VM.</p>
  443. * @param var environment variable to be added
  444. * @since Ant 1.5
  445. */
  446. public void addEnv(Environment.Variable var) {
  447. env.addVariable(var);
  448. }
  449. /**
  450. * If true, use a new environment when forked.
  451. *
  452. * <p>Will be ignored if we are not forking a new VM.</p>
  453. *
  454. * @param newenv boolean indicating if setting a new environment is wished
  455. * @since Ant 1.5
  456. */
  457. public void setNewenvironment(boolean newenv) {
  458. newEnvironment = newenv;
  459. }
  460. /**
  461. * Add a new single testcase.
  462. * @param test a new single testcase
  463. * @see JUnitTest
  464. *
  465. * @since Ant 1.2
  466. */
  467. public void addTest(JUnitTest test) {
  468. tests.addElement(test);
  469. }
  470. /**
  471. * Adds a set of tests based on pattern matching.
  472. *
  473. * @return a new instance of a batch test.
  474. * @see BatchTest
  475. *
  476. * @since Ant 1.2
  477. */
  478. public BatchTest createBatchTest() {
  479. BatchTest test = new BatchTest(getProject());
  480. batchTests.addElement(test);
  481. return test;
  482. }
  483. /**
  484. * Add a new formatter to all tests of this task.
  485. *
  486. * @param fe formatter element
  487. * @since Ant 1.2
  488. */
  489. public void addFormatter(FormatterElement fe) {
  490. formatters.addElement(fe);
  491. }
  492. /**
  493. * If true, include ant.jar, optional.jar and junit.jar in the forked VM.
  494. *
  495. * @param b include ant run time yes or no
  496. * @since Ant 1.5
  497. */
  498. public void setIncludeantruntime(boolean b) {
  499. includeAntRuntime = b;
  500. }
  501. /**
  502. * If true, send any output generated by tests to Ant's logging system
  503. * as well as to the formatters.
  504. * By default only the formatters receive the output.
  505. *
  506. * <p>Output will always be passed to the formatters and not by
  507. * shown by default. This option should for example be set for
  508. * tests that are interactive and prompt the user to do
  509. * something.</p>
  510. *
  511. * @param showOutput if true, send output to Ant's logging system too
  512. * @since Ant 1.5
  513. */
  514. public void setShowOutput(boolean showOutput) {
  515. this.showOutput = showOutput;
  516. }
  517. /**
  518. * Assertions to enable in this program (if fork=true)
  519. * @since Ant 1.6
  520. * @param asserts assertion set
  521. */
  522. public void addAssertions(Assertions asserts) {
  523. if (getCommandline().getAssertions() != null) {
  524. throw new BuildException("Only one assertion declaration is allowed");
  525. }
  526. getCommandline().setAssertions(asserts);
  527. }
  528. /**
  529. * Sets the permissions for the application run inside the same JVM.
  530. * @since Ant 1.6
  531. * @return .
  532. */
  533. public Permissions createPermissions() {
  534. if (perm == null) {
  535. perm = new Permissions();
  536. }
  537. return perm;
  538. }
  539. /**
  540. * Creates a new JUnitRunner and enables fork of a new Java VM.
  541. *
  542. * @throws Exception under ??? circumstances
  543. * @since Ant 1.2
  544. */
  545. public JUnitTask() throws Exception {
  546. getCommandline()
  547. .setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
  548. }
  549. /**
  550. * Where Ant should place temporary files.
  551. *
  552. * @param tmpDir location where temporary files should go to
  553. * @since Ant 1.6
  554. */
  555. public void setTempdir(File tmpDir) {
  556. if (tmpDir!=null) {
  557. if (!tmpDir.exists() || !tmpDir.isDirectory()) {
  558. throw new BuildException(tmpDir.toString()
  559. +" is not a valid temp directory");
  560. }
  561. }
  562. this.tmpDir = tmpDir;
  563. }
  564. /**
  565. * Adds the jars or directories containing Ant, this task and
  566. * JUnit to the classpath - this should make the forked JVM work
  567. * without having to specify them directly.
  568. *
  569. * @since Ant 1.4
  570. */
  571. public void init() {
  572. antRuntimeClasses = new Path(getProject());
  573. addClasspathEntry("/junit/framework/TestCase.class");
  574. addClasspathEntry("/org/apache/tools/ant/launch/AntMain.class");
  575. addClasspathEntry("/org/apache/tools/ant/Task.class");
  576. addClasspathEntry("/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.class");
  577. }
  578. /**
  579. * Runs the testcase.
  580. *
  581. * @throws BuildException in case of test failures or errors
  582. * @since Ant 1.2
  583. */
  584. public void execute() throws BuildException {
  585. List testLists = new ArrayList();
  586. boolean forkPerTest = forkMode.getValue().equals(ForkMode.PER_TEST);
  587. if (forkPerTest || forkMode.getValue().equals(ForkMode.ONCE)) {
  588. testLists.addAll(executeOrQueue(getIndividualTests(),
  589. forkPerTest));
  590. } else { /* forkMode.getValue().equals(ForkMode.PER_BATCH) */
  591. final int count = batchTests.size();
  592. for (int i = 0; i < count; i++) {
  593. BatchTest batchtest = (BatchTest) batchTests.elementAt(i);
  594. testLists.addAll(executeOrQueue(batchtest.elements(), false));
  595. }
  596. testLists.addAll(executeOrQueue(tests.elements(), forkPerTest));
  597. }
  598. Iterator iter = testLists.iterator();
  599. while (iter.hasNext()) {
  600. List l = (List) iter.next();
  601. if (l.size() == 1) {
  602. execute((JUnitTest) l.get(0));
  603. } else {
  604. execute(l);
  605. }
  606. }
  607. }
  608. /**
  609. * Run the tests.
  610. * @param arg one JunitTest
  611. * @throws BuildException in case of test failures or errors
  612. */
  613. protected void execute(JUnitTest arg) throws BuildException {
  614. JUnitTest test = (JUnitTest) arg.clone();
  615. // set the default values if not specified
  616. //@todo should be moved to the test class instead.
  617. if (test.getTodir() == null) {
  618. test.setTodir(getProject().resolveFile("."));
  619. }
  620. if (test.getOutfile() == null) {
  621. test.setOutfile("TEST-" + test.getName());
  622. }
  623. // execute the test and get the return code
  624. int exitValue = JUnitTestRunner.ERRORS;
  625. boolean wasKilled = false;
  626. if (!test.getFork()) {
  627. exitValue = executeInVM(test);
  628. } else {
  629. ExecuteWatchdog watchdog = createWatchdog();
  630. exitValue = executeAsForked(test, watchdog, null);
  631. // null watchdog means no timeout, you'd better not check with null
  632. if (watchdog != null) {
  633. wasKilled = watchdog.killedProcess();
  634. }
  635. }
  636. actOnTestResult(exitValue, wasKilled, test, "Test " + test.getName());
  637. }
  638. /**
  639. * Execute a list of tests in a single forked Java VM.
  640. */
  641. protected void execute(List tests) throws BuildException {
  642. JUnitTest test = null;
  643. // Create a temporary file to pass the test cases to run to
  644. // the runner (one test case per line)
  645. File casesFile = createTempPropertiesFile("junittestcases");
  646. PrintWriter writer = null;
  647. try {
  648. writer =
  649. new PrintWriter(new BufferedWriter(new FileWriter(casesFile)));
  650. Iterator iter = tests.iterator();
  651. while (iter.hasNext()) {
  652. test = (JUnitTest) iter.next();
  653. writer.print(test.getName());
  654. if (test.getTodir() == null) {
  655. writer.print("," + getProject().resolveFile("."));
  656. } else {
  657. writer.print("," + test.getTodir());
  658. }
  659. if (test.getOutfile() == null) {
  660. writer.println("," + "TEST-" + test.getName());
  661. } else {
  662. writer.println("," + test.getOutfile());
  663. }
  664. }
  665. writer.flush();
  666. writer.close();
  667. writer = null;
  668. // execute the test and get the return code
  669. int exitValue = JUnitTestRunner.ERRORS;
  670. boolean wasKilled = false;
  671. ExecuteWatchdog watchdog = createWatchdog();
  672. exitValue = executeAsForked(test, watchdog, casesFile);
  673. // null watchdog means no timeout, you'd better not check
  674. // with null
  675. if (watchdog != null) {
  676. wasKilled = watchdog.killedProcess();
  677. }
  678. actOnTestResult(exitValue, wasKilled, test, "Tests");
  679. } catch(IOException e) {
  680. log(e.toString(), Project.MSG_ERR);
  681. throw new BuildException(e);
  682. } finally {
  683. if (writer != null) {
  684. writer.close();
  685. }
  686. try {
  687. casesFile.delete();
  688. } catch (Exception e) {
  689. log(e.toString(), Project.MSG_ERR);
  690. }
  691. }
  692. }
  693. /**
  694. * Execute a testcase by forking a new JVM. The command will block until
  695. * it finishes. To know if the process was destroyed or not, use the
  696. * <tt>killedProcess()</tt> method of the watchdog class.
  697. * @param test the testcase to execute.
  698. * @param watchdog the watchdog in charge of cancelling the test if it
  699. * exceeds a certain amount of time. Can be <tt>null</tt>, in this case
  700. * the test could probably hang forever.
  701. * @throws BuildException in case of error creating a temporary property file,
  702. * or if the junit process can not be forked
  703. */
  704. private int executeAsForked(JUnitTest test, ExecuteWatchdog watchdog,
  705. File casesFile)
  706. throws BuildException {
  707. if (perm != null) {
  708. log("Permissions ignored when running in forked mode!",
  709. Project.MSG_WARN);
  710. }
  711. CommandlineJava cmd = (CommandlineJava) getCommandline().clone();
  712. cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
  713. if (casesFile == null) {
  714. cmd.createArgument().setValue(test.getName());
  715. } else {
  716. log("Running multiple tests in the same VM", Project.MSG_VERBOSE);
  717. cmd.createArgument().setValue("testsfile=" + casesFile);
  718. }
  719. cmd.createArgument().setValue("filtertrace=" + test.getFiltertrace());
  720. cmd.createArgument().setValue("haltOnError=" + test.getHaltonerror());
  721. cmd.createArgument().setValue("haltOnFailure="
  722. + test.getHaltonfailure());
  723. if (includeAntRuntime) {
  724. Vector v = Execute.getProcEnvironment();
  725. Enumeration e = v.elements();
  726. while (e.hasMoreElements()) {
  727. String s = (String) e.nextElement();
  728. if (s.startsWith("CLASSPATH=")) {
  729. cmd.createClasspath(getProject()).createPath()
  730. .append(new Path(getProject(),
  731. s.substring(10 // "CLASSPATH=".length()
  732. )));
  733. }
  734. }
  735. log("Implicitly adding " + antRuntimeClasses + " to CLASSPATH",
  736. Project.MSG_VERBOSE);
  737. cmd.createClasspath(getProject()).createPath()
  738. .append(antRuntimeClasses);
  739. }
  740. if (summary) {
  741. log("Running " + test.getName(), Project.MSG_INFO);
  742. cmd.createArgument()
  743. .setValue("formatter"
  744. + "=org.apache.tools.ant.taskdefs.optional.junit.SummaryJUnitResultFormatter");
  745. }
  746. cmd.createArgument().setValue("showoutput="
  747. + String.valueOf(showOutput));
  748. StringBuffer formatterArg = new StringBuffer(STRING_BUFFER_SIZE);
  749. final FormatterElement[] feArray = mergeFormatters(test);
  750. for (int i = 0; i < feArray.length; i++) {
  751. FormatterElement fe = feArray[i];
  752. if (fe.shouldUse(this)) {
  753. formatterArg.append("formatter=");
  754. formatterArg.append(fe.getClassname());
  755. File outFile = getOutput(fe, test);
  756. if (outFile != null) {
  757. formatterArg.append(",");
  758. formatterArg.append(outFile);
  759. }
  760. cmd.createArgument().setValue(formatterArg.toString());
  761. formatterArg = new StringBuffer();
  762. }
  763. }
  764. File propsFile = createTempPropertiesFile("junit");
  765. cmd.createArgument().setValue("propsfile="
  766. + propsFile.getAbsolutePath());
  767. Hashtable p = getProject().getProperties();
  768. Properties props = new Properties();
  769. for (Enumeration e = p.keys(); e.hasMoreElements();) {
  770. Object key = e.nextElement();
  771. props.put(key, p.get(key));
  772. }
  773. try {
  774. FileOutputStream outstream = new FileOutputStream(propsFile);
  775. props.store(outstream, "Ant JUnitTask generated properties file");
  776. outstream.close();
  777. } catch (java.io.IOException e) {
  778. propsFile.delete();
  779. throw new BuildException("Error creating temporary properties "
  780. + "file.", e, getLocation());
  781. }
  782. Execute execute = new Execute(new LogStreamHandler(this,
  783. Project.MSG_INFO,
  784. Project.MSG_WARN),
  785. watchdog);
  786. execute.setCommandline(cmd.getCommandline());
  787. execute.setAntRun(getProject());
  788. if (dir != null) {
  789. execute.setWorkingDirectory(dir);
  790. }
  791. String[] environment = env.getVariables();
  792. if (environment != null) {
  793. for (int i = 0; i < environment.length; i++) {
  794. log("Setting environment variable: " + environment[i],
  795. Project.MSG_VERBOSE);
  796. }
  797. }
  798. execute.setNewenvironment(newEnvironment);
  799. execute.setEnvironment(environment);
  800. log(cmd.describeCommand(), Project.MSG_VERBOSE);
  801. int retVal;
  802. try {
  803. retVal = execute.execute();
  804. } catch (IOException e) {
  805. throw new BuildException("Process fork failed.", e, getLocation());
  806. } finally {
  807. if (watchdog != null && watchdog.killedProcess()) {
  808. logTimeout(feArray, test);
  809. }
  810. if (!propsFile.delete()) {
  811. throw new BuildException("Could not delete temporary "
  812. + "properties file.");
  813. }
  814. }
  815. return retVal;
  816. }
  817. /**
  818. * Create a temporary file to pass the properties to a new process.
  819. * Will auto-delete on (graceful) exit.
  820. * The file will be in the project basedir unless tmpDir declares
  821. * something else.
  822. * @param prefix
  823. * @return
  824. */
  825. private File createTempPropertiesFile(String prefix) {
  826. File propsFile =
  827. FileUtils.newFileUtils().createTempFile(prefix, ".properties",
  828. tmpDir != null ? tmpDir : getProject().getBaseDir());
  829. propsFile.deleteOnExit();
  830. return propsFile;
  831. }
  832. /**
  833. * Pass output sent to System.out to the TestRunner so it can
  834. * collect ot for the formatters.
  835. *
  836. * @param output output coming from System.out
  837. * @since Ant 1.5
  838. */
  839. protected void handleOutput(String output) {
  840. if (runner != null) {
  841. runner.handleOutput(output);
  842. if (showOutput) {
  843. super.handleOutput(output);
  844. }
  845. } else {
  846. super.handleOutput(output);
  847. }
  848. }
  849. /**
  850. * @see Task#handleInput(byte[], int, int)
  851. *
  852. * @since Ant 1.6
  853. */
  854. protected int handleInput(byte[] buffer, int offset, int length)
  855. throws IOException {
  856. if (runner != null) {
  857. return runner.handleInput(buffer, offset, length);
  858. } else {
  859. return super.handleInput(buffer, offset, length);
  860. }
  861. }
  862. /**
  863. * Pass output sent to System.out to the TestRunner so it can
  864. * collect ot for the formatters.
  865. *
  866. * @param output output coming from System.out
  867. * @since Ant 1.5.2
  868. */
  869. protected void handleFlush(String output) {
  870. if (runner != null) {
  871. runner.handleFlush(output);
  872. if (showOutput) {
  873. super.handleFlush(output);
  874. }
  875. } else {
  876. super.handleFlush(output);
  877. }
  878. }
  879. /**
  880. * Pass output sent to System.err to the TestRunner so it can
  881. * collect it for the formatters.
  882. *
  883. * @param output output coming from System.err
  884. * @since Ant 1.5
  885. */
  886. public void handleErrorOutput(String output) {
  887. if (runner != null) {
  888. runner.handleErrorOutput(output);
  889. if (showOutput) {
  890. super.handleErrorOutput(output);
  891. }
  892. } else {
  893. super.handleErrorOutput(output);
  894. }
  895. }
  896. /**
  897. * Pass output sent to System.err to the TestRunner so it can
  898. * collect it for the formatters.
  899. *
  900. * @param output coming from System.err
  901. * @since Ant 1.5.2
  902. */
  903. public void handleErrorFlush(String output) {
  904. if (runner != null) {
  905. runner.handleErrorFlush(output);
  906. if (showOutput) {
  907. super.handleErrorFlush(output);
  908. }
  909. } else {
  910. super.handleErrorFlush(output);
  911. }
  912. }
  913. // in VM is not very nice since it could probably hang the
  914. // whole build. IMHO this method should be avoided and it would be best
  915. // to remove it in future versions. TBD. (SBa)
  916. /**
  917. * Execute inside VM.
  918. * @param arg one JUnitTest
  919. * @throws BuildException under unspecified circumstances
  920. */
  921. private int executeInVM(JUnitTest arg) throws BuildException {
  922. JUnitTest test = (JUnitTest) arg.clone();
  923. test.setProperties(getProject().getProperties());
  924. if (dir != null) {
  925. log("dir attribute ignored if running in the same VM",
  926. Project.MSG_WARN);
  927. }
  928. if (newEnvironment || null != env.getVariables()) {
  929. log("Changes to environment variables are ignored if running in "
  930. + "the same VM.", Project.MSG_WARN);
  931. }
  932. if (getCommandline().getBootclasspath() != null) {
  933. log("bootclasspath is ignored if running in the same VM.",
  934. Project.MSG_WARN);
  935. }
  936. CommandlineJava.SysProperties sysProperties =
  937. getCommandline().getSystemProperties();
  938. if (sysProperties != null) {
  939. sysProperties.setSystem();
  940. }
  941. try {
  942. log("Using System properties " + System.getProperties(),
  943. Project.MSG_VERBOSE);
  944. createClassLoader();
  945. if (classLoader != null) {
  946. classLoader.setThreadContextLoader();
  947. }
  948. runner = new JUnitTestRunner(test, test.getHaltonerror(),
  949. test.getFiltertrace(),
  950. test.getHaltonfailure(), classLoader);
  951. if (summary) {
  952. log("Running " + test.getName(), Project.MSG_INFO);
  953. SummaryJUnitResultFormatter f =
  954. new SummaryJUnitResultFormatter();
  955. f.setWithOutAndErr("withoutanderr"
  956. .equalsIgnoreCase(summaryValue));
  957. f.setOutput(getDefaultOutput());
  958. runner.addFormatter(f);
  959. }
  960. runner.setPermissions(perm);
  961. final FormatterElement[] feArray = mergeFormatters(test);
  962. for (int i = 0; i < feArray.length; i++) {
  963. FormatterElement fe = feArray[i];
  964. if (fe.shouldUse(this)) {
  965. File outFile = getOutput(fe, test);
  966. if (outFile != null) {
  967. fe.setOutfile(outFile);
  968. } else {
  969. fe.setOutput(getDefaultOutput());
  970. }
  971. runner.addFormatter(fe.createFormatter(classLoader));
  972. }
  973. }
  974. runner.run();
  975. return runner.getRetCode();
  976. } finally {
  977. if (sysProperties != null) {
  978. sysProperties.restoreSystem();
  979. }
  980. if (classLoader != null) {
  981. classLoader.resetThreadContextLoader();
  982. }
  983. }
  984. }
  985. /**
  986. * @return <tt>null</tt> if there is a timeout value, otherwise the
  987. * watchdog instance.
  988. *
  989. * @throws BuildException under unspecified circumstances
  990. * @since Ant 1.2
  991. */
  992. protected ExecuteWatchdog createWatchdog() throws BuildException {
  993. if (timeout == null) {
  994. return null;
  995. }
  996. return new ExecuteWatchdog((long) timeout.intValue());
  997. }
  998. /**
  999. * Get the default output for a formatter.
  1000. *
  1001. * @return default output stream for a formatter
  1002. * @since Ant 1.3
  1003. */
  1004. protected OutputStream getDefaultOutput() {
  1005. return new LogOutputStream(this, Project.MSG_INFO);
  1006. }
  1007. /**
  1008. * Merge all individual tests from the batchtest with all individual tests
  1009. * and return an enumeration over all <tt>JUnitTest</tt>.
  1010. *
  1011. * @return enumeration over individual tests
  1012. * @since Ant 1.3
  1013. */
  1014. protected Enumeration getIndividualTests() {
  1015. final int count = batchTests.size();
  1016. final Enumeration[] enums = new Enumeration[ count + 1];
  1017. for (int i = 0; i < count; i++) {
  1018. BatchTest batchtest = (BatchTest) batchTests.elementAt(i);
  1019. enums[i] = batchtest.elements();
  1020. }
  1021. enums[enums.length - 1] = tests.elements();
  1022. return Enumerations.fromCompound(enums);
  1023. }
  1024. /**
  1025. * return an enumeration listing each test, then each batchtest
  1026. * @return enumeration
  1027. * @since Ant 1.3
  1028. */
  1029. protected Enumeration allTests() {
  1030. Enumeration[] enums = {tests.elements(), batchTests.elements()};
  1031. return Enumerations.fromCompound(enums);
  1032. }
  1033. /**
  1034. * @param test junit test
  1035. * @return array of FormatterElement
  1036. * @since Ant 1.3
  1037. */
  1038. private FormatterElement[] mergeFormatters(JUnitTest test) {
  1039. Vector feVector = (Vector) formatters.clone();
  1040. test.addFormattersTo(feVector);
  1041. FormatterElement[] feArray = new FormatterElement[feVector.size()];
  1042. feVector.copyInto(feArray);
  1043. return feArray;
  1044. }
  1045. /**
  1046. * If the formatter sends output to a file, return that file.
  1047. * null otherwise.
  1048. * @param fe formatter element
  1049. * @param test one JUnit test
  1050. * @return file reference
  1051. * @since Ant 1.3
  1052. */
  1053. protected File getOutput(FormatterElement fe, JUnitTest test) {
  1054. if (fe.getUseFile()) {
  1055. String filename = test.getOutfile() + fe.getExtension();
  1056. File destFile = new File(test.getTodir(), filename);
  1057. String absFilename = destFile.getAbsolutePath();
  1058. return getProject().resolveFile(absFilename);
  1059. }
  1060. return null;
  1061. }
  1062. /**
  1063. * Search for the given resource and add the directory or archive
  1064. * that contains it to the classpath.
  1065. *
  1066. * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
  1067. * getResource doesn't contain the name of the archive.</p>
  1068. *
  1069. * @param resource resource that one wants to lookup
  1070. * @since Ant 1.4
  1071. */
  1072. protected void addClasspathEntry(String resource) {
  1073. /*
  1074. * pre Ant 1.6 this method used to call getClass().getResource
  1075. * while Ant 1.6 will call ClassLoader.getResource().
  1076. *
  1077. * The difference is that Class.getResource expects a leading
  1078. * slash for "absolute" resources and will strip it before
  1079. * delegating to ClassLoader.getResource - so we now have to
  1080. * emulate Class's behavior.
  1081. */
  1082. if (resource.startsWith("/")) {
  1083. resource = resource.substring(1);
  1084. } else {
  1085. resource = "org/apache/tools/ant/taskdefs/optional/junit/"
  1086. + resource;
  1087. }
  1088. File f = LoaderUtils.getResourceSource(getClass().getClassLoader(),
  1089. resource);
  1090. if (f != null) {
  1091. log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
  1092. antRuntimeClasses.createPath().setLocation(f);
  1093. } else {
  1094. log("Couldn\'t find " + resource, Project.MSG_DEBUG);
  1095. }
  1096. }
  1097. /**
  1098. * Take care that some output is produced in report files if the
  1099. * watchdog kills the test.
  1100. *
  1101. * @since Ant 1.5.2
  1102. */
  1103. private void logTimeout(FormatterElement[] feArray, JUnitTest test) {
  1104. createClassLoader();
  1105. test.setCounts(1, 0, 1);
  1106. test.setProperties(getProject().getProperties());
  1107. for (int i = 0; i < feArray.length; i++) {
  1108. FormatterElement fe = feArray[i];
  1109. File outFile = getOutput(fe, test);
  1110. JUnitResultFormatter formatter = fe.createFormatter(classLoader);
  1111. if (outFile != null && formatter != null) {
  1112. try {
  1113. OutputStream out = new FileOutputStream(outFile);
  1114. addTimeout(test, formatter, out);
  1115. } catch (IOException e) {
  1116. // ignore
  1117. }
  1118. }
  1119. }
  1120. if (summary) {
  1121. SummaryJUnitResultFormatter f = new SummaryJUnitResultFormatter();
  1122. f.setWithOutAndErr("withoutanderr".equalsIgnoreCase(summaryValue));
  1123. addTimeout(test, f, getDefaultOutput());
  1124. }
  1125. }
  1126. /**
  1127. * Adds the actual timeout to the formatter.
  1128. * Only used from the logTimeout method.
  1129. * @since Ant 1.6
  1130. */
  1131. private void addTimeout(JUnitTest test, JUnitResultFormatter formatter,
  1132. OutputStream out) {
  1133. formatter.setOutput(out);
  1134. formatter.startTestSuite(test);
  1135. //the trick to integrating test output to the formatter, is to
  1136. //create a special test class that asserts a timout occurred,
  1137. //and tell the formatter that it raised.
  1138. Test t = new Test() {
  1139. public int countTestCases() { return 1; }
  1140. public void run(TestResult r) {
  1141. throw new AssertionFailedError("Timeout occurred");
  1142. }
  1143. };
  1144. formatter.startTest(t);
  1145. formatter.addError(t, new AssertionFailedError("Timeout occurred"));
  1146. formatter.endTestSuite(test);
  1147. }
  1148. /**
  1149. * Creates and configures an AntClassLoader instance from the
  1150. * nested classpath element.
  1151. *
  1152. * @since Ant 1.6
  1153. */
  1154. private void createClassLoader() {
  1155. Path userClasspath = getCommandline().getClasspath();
  1156. if (userClasspath != null) {
  1157. if (reloading || classLoader == null) {
  1158. Path classpath = (Path) userClasspath.clone();
  1159. if (includeAntRuntime) {
  1160. log("Implicitly adding " + antRuntimeClasses
  1161. + " to CLASSPATH", Project.MSG_VERBOSE);
  1162. classpath.append(antRuntimeClasses);
  1163. }
  1164. classLoader = getProject().createClassLoader(classpath);
  1165. log("Using CLASSPATH " + classLoader.getClasspath(),
  1166. Project.MSG_VERBOSE);
  1167. classLoader.setParentFirst(false);
  1168. classLoader.addJavaLibraries();
  1169. log("Using CLASSPATH " + classLoader.getClasspath(), Project.MSG_VERBOSE);
  1170. // make sure the test will be accepted as a TestCase
  1171. classLoader.addSystemPackageRoot("junit");
  1172. // will cause trouble in JDK 1.1 if omitted
  1173. classLoader.addSystemPackageRoot("org.apache.tools.ant");
  1174. }
  1175. }
  1176. }
  1177. /**
  1178. * @since Ant 1.6.2
  1179. */
  1180. protected CommandlineJava getCommandline() {
  1181. if (commandline == null) {
  1182. commandline = new CommandlineJava();
  1183. }
  1184. return commandline;
  1185. }
  1186. /**
  1187. * Forked test support
  1188. * @since Ant 1.6.2
  1189. */
  1190. private final class ForkedTestConfiguration {
  1191. private boolean filterTrace;
  1192. private boolean haltOnError;
  1193. private boolean haltOnFailure;
  1194. private String errorProperty;
  1195. private String failureProperty;
  1196. /**
  1197. * constructor for forked test configuration
  1198. * @param filterTrace
  1199. * @param haltOnError
  1200. * @param haltOnFailure
  1201. * @param errorProperty
  1202. * @param failureProperty
  1203. */
  1204. ForkedTestConfiguration(boolean filterTrace, boolean haltOnError,
  1205. boolean haltOnFailure, String errorProperty,
  1206. String failureProperty) {
  1207. this.filterTrace = filterTrace;
  1208. this.haltOnError = haltOnError;
  1209. this.haltOnFailure = haltOnFailure;
  1210. this.errorProperty = errorProperty;
  1211. this.failureProperty = failureProperty;
  1212. }
  1213. /**
  1214. * configure from a test; sets member variables to attributes of the test
  1215. * @param test
  1216. */
  1217. ForkedTestConfiguration(JUnitTest test) {
  1218. this(test.getFiltertrace(),
  1219. test.getHaltonerror(),
  1220. test.getHaltonfailure(),
  1221. test.getErrorProperty(),
  1222. test.getFailureProperty());
  1223. }
  1224. /**
  1225. * equality test checks all the member variables
  1226. * @param other
  1227. * @return true if everything is equal
  1228. */
  1229. public boolean equals(Object other) {
  1230. if (other == null
  1231. || other.getClass() != ForkedTestConfiguration.class) {
  1232. return false;
  1233. }
  1234. ForkedTestConfiguration o = (ForkedTestConfiguration) other;
  1235. return filterTrace == o.filterTrace
  1236. && haltOnError == o.haltOnError
  1237. && haltOnFailure == o.haltOnFailure
  1238. && ((errorProperty == null && o.errorProperty == null)
  1239. ||
  1240. (errorProperty != null
  1241. && errorProperty.equals(o.errorProperty)))
  1242. && ((failureProperty == null && o.failureProperty == null)
  1243. ||
  1244. (failureProperty != null
  1245. && failureProperty.equals(o.failureProperty)));
  1246. }
  1247. /**
  1248. * hashcode is based only on the boolean members, and returns a value
  1249. * in the range 0-7.
  1250. * @return
  1251. */
  1252. public int hashCode() {
  1253. return (filterTrace ? 1 : 0)
  1254. + (haltOnError ? 2 : 0)
  1255. + (haltOnFailure ? 4 : 0);
  1256. }
  1257. }
  1258. /**
  1259. * These are the different forking options
  1260. * @since 1.6.2
  1261. */
  1262. public static final class ForkMode extends EnumeratedAttribute {
  1263. /**
  1264. * fork once only
  1265. */
  1266. public static final String ONCE = "once";
  1267. /**
  1268. * fork once per test class
  1269. */
  1270. public static final String PER_TEST = "perTest";
  1271. /**
  1272. * fork once per batch of tests
  1273. */
  1274. public static final String PER_BATCH = "perBatch";
  1275. public ForkMode() {
  1276. super();
  1277. }
  1278. public ForkMode(String value) {
  1279. super();
  1280. setValue(value);
  1281. }
  1282. public String[] getValues() {
  1283. return new String[] {ONCE, PER_TEST, PER_BATCH};
  1284. }
  1285. }
  1286. /**
  1287. * Executes all tests that don't need to be forked (or all tests
  1288. * if the runIndividual argument is true. Returns a collection of
  1289. * lists of tests that share the same VM configuration and haven't
  1290. * been executed yet.
  1291. *
  1292. * @since 1.6.2
  1293. */
  1294. protected Collection executeOrQueue(Enumeration testList,
  1295. boolean runIndividual) {
  1296. Map testConfigurations = new HashMap();
  1297. while (testList.hasMoreElements()) {
  1298. JUnitTest test = (JUnitTest) testList.nextElement();
  1299. if (test.shouldRun(getProject())) {
  1300. if (runIndividual || !test.getFork()) {
  1301. execute(test);
  1302. } else {
  1303. ForkedTestConfiguration c =
  1304. new ForkedTestConfiguration(test);
  1305. List l = (List) testConfigurations.get(c);
  1306. if (l == null) {
  1307. l = new ArrayList();
  1308. testConfigurations.put(c, l);
  1309. }
  1310. l.add(test);
  1311. }
  1312. }
  1313. }
  1314. return testConfigurations.values();
  1315. }
  1316. /**
  1317. * Logs information about failed tests, potentially stops
  1318. * processing (by throwing a BuildException) if a failure/error
  1319. * occured or sets a property.
  1320. *
  1321. * @since Ant 1.6.2
  1322. */
  1323. protected void actOnTestResult(int exitValue, boolean wasKilled,
  1324. JUnitTest test, String name) {
  1325. // if there is an error/failure and that it should halt, stop
  1326. // everything otherwise just log a statement
  1327. boolean errorOccurredHere =
  1328. exitValue == JUnitTestRunner.ERRORS || wasKilled;
  1329. boolean failureOccurredHere =
  1330. exitValue != JUnitTestRunner.SUCCESS || wasKilled;
  1331. if (errorOccurredHere || failureOccurredHere) {
  1332. if ((errorOccurredHere && test.getHaltonerror())
  1333. || (failureOccurredHere && test.getHaltonfailure())) {
  1334. throw new BuildException(name + " failed"
  1335. + (wasKilled ? " (timeout)" : ""), getLocation());
  1336. } else {
  1337. log(name + " FAILED"
  1338. + (wasKilled ? " (timeout)" : ""), Project.MSG_ERR);
  1339. if (errorOccurredHere && test.getErrorProperty() != null) {
  1340. getProject().setNewProperty(test.getErrorProperty(), "true");
  1341. }
  1342. if (failureOccurredHere && test.getFailureProperty() != null) {
  1343. getProject().setNewProperty(test.getFailureProperty(), "true");
  1344. }
  1345. }
  1346. }
  1347. }
  1348. }