This is an automated email from the ASF dual-hosted git repository.

jaikiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ant.git


The following commit(s) were added to refs/heads/master by this push:
     new 89b0895ad junitlauncher - timeout should apply to all tests combined 
when using forkMode=perTestClass
89b0895ad is described below

commit 89b0895adc5dec7990c18731743d7a9d9f8ee283
Author: Jaikiran Pai <[email protected]>
AuthorDate: Wed Aug 16 13:25:48 2023 +0530

    junitlauncher - timeout should apply to all tests combined when using 
forkMode=perTestClass
---
 manual/Tasks/junitlauncher.html                    |  6 +++-
 .../junitlauncher/confined/JUnitLauncherTask.java  | 40 +++++++++++++++++-----
 2 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/manual/Tasks/junitlauncher.html b/manual/Tasks/junitlauncher.html
index 2e33a17c4..ed4f4358b 100644
--- a/manual/Tasks/junitlauncher.html
+++ b/manual/Tasks/junitlauncher.html
@@ -645,7 +645,11 @@ the new JVM instance that will be created to launch the 
tests.
         <td>Controls how many JVMs are launched for the forked tests. Allowed 
values are:
             <ul class="inlinelist">
                 <li><code>perTestClass</code> - This mode launches each test 
class in a
-                    separately forked JVM</li>
+                    separately forked JVM. Each of these JVMs will be forked 
sequentially
+                    one at a time, as and when each test class execution 
completes.
+                    If any <code>timeout</code> value is specified, then that 
timeout applies to
+                    the time that all tests use together, not to an individual 
test.
+                </li>
             </ul>
             <p><em>Since Ant 1.10.14</em></p>
         </td>
diff --git 
a/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/JUnitLauncherTask.java
 
b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/JUnitLauncherTask.java
index 6dca664a4..15f685666 100644
--- 
a/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/JUnitLauncherTask.java
+++ 
b/src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/JUnitLauncherTask.java
@@ -42,11 +42,14 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.Optional;
 import java.util.Properties;
 import java.util.StringTokenizer;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
 
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
 import static 
org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_EXCLUDE_TAGS;
 import static 
org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
 import static 
org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_INCLUDE_TAGS;
@@ -82,8 +85,8 @@ public class JUnitLauncherTask extends Task {
     private boolean printSummary;
     private final List<TestDefinition> tests = new ArrayList<>();
     private final List<ListenerDefinition> listeners = new ArrayList<>();
-    private List<String> includeTags = new ArrayList<>();
-    private List<String> excludeTags = new ArrayList<>();
+    private final List<String> includeTags = new ArrayList<>();
+    private final List<String> excludeTags = new ArrayList<>();
 
     public JUnitLauncherTask() {
     }
@@ -105,8 +108,13 @@ public class JUnitLauncherTask extends Task {
                 launchViaReflection(new 
InVMLaunch(Collections.singletonList(test)));
             } else {
                 final List<ForkedRepresentation> forkedReps = 
test.toForkedRepresentations();
+                final long timeout = forkDefinition.getTimeout(); // in millis
+                // compute the "end time" (if any)
+                final Optional<Long> deadlineNanos = timeout == -1
+                        ? Optional.empty() // no timeout
+                        : Optional.of(System.nanoTime() + 
MILLISECONDS.toNanos(timeout));
                 for (final ForkedRepresentation forkedRep : forkedReps) {
-                    forkTest(test, forkDefinition, forkedRep);
+                    forkTest(test, forkDefinition, forkedRep, deadlineNanos);
                 }
             }
         }
@@ -244,7 +252,8 @@ public class JUnitLauncherTask extends Task {
     }
 
     private void forkTest(final TestDefinition test, final ForkDefinition 
forkDefinition,
-                          final ForkedRepresentation forkedRepresentation) {
+                          final ForkedRepresentation forkedRepresentation,
+                          final Optional<Long> deadlineNanos) {
         // create launch command
         final CommandlineJava commandlineJava = 
forkDefinition.generateCommandLine(this);
         if (this.classPath != null) {
@@ -302,7 +311,7 @@ public class JUnitLauncherTask extends Task {
         
commandlineJava.createArgument().setValue(launchDefXmlPath.toAbsolutePath().toString());
 
         // launch the process and wait for process to complete
-        final int exitCode = executeForkedTest(forkDefinition, 
commandlineJava);
+        final int exitCode = executeForkedTest(forkDefinition, 
commandlineJava, deadlineNanos);
         switch (exitCode) {
             case Constants.FORK_EXIT_CODE_SUCCESS: {
                 // success
@@ -359,11 +368,26 @@ public class JUnitLauncherTask extends Task {
                 .collect(Collectors.joining(", "));
     }
 
-    private int executeForkedTest(final ForkDefinition forkDefinition, final 
CommandlineJava commandlineJava) {
+    private int executeForkedTest(final ForkDefinition forkDefinition, final 
CommandlineJava commandlineJava,
+                                  final Optional<Long> deadlineNanos) {
         final LogOutputStream outStream = new LogOutputStream(this, 
Project.MSG_INFO);
         final LogOutputStream errStream = new LogOutputStream(this, 
Project.MSG_WARN);
-        final ExecuteWatchdog watchdog = forkDefinition.getTimeout() > 0
-                ? createExecuteWatchdog(forkDefinition.getTimeout()) : null;
+        final ExecuteWatchdog watchdog;
+        if (deadlineNanos.isPresent()) {
+            final long remainingNanos = deadlineNanos.get() - 
System.nanoTime();
+            if (remainingNanos <= 0) {
+                // already timed out
+                return Constants.FORK_EXIT_CODE_TIMED_OUT;
+            }
+            final long timeoutInMillis = NANOSECONDS.toMillis(remainingNanos);
+            if (timeoutInMillis == 0) {
+                // already timed out
+                return Constants.FORK_EXIT_CODE_TIMED_OUT;
+            }
+            watchdog = createExecuteWatchdog(timeoutInMillis);
+        } else {
+            watchdog = null; // no timeout specified
+        }
         final Execute execute = new Execute(new PumpStreamHandler(outStream, 
errStream), watchdog);
         execute.setCommandline(commandlineJava.getCommandline());
         execute.setAntRun(getProject());

Reply via email to