Skip to content

Commit df9d846

Browse files
committed
junitlauncher - Added fork mode support
1 parent 002596a commit df9d846

7 files changed

Lines changed: 149 additions & 3 deletions

File tree

manual/Tasks/junitlauncher.html

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -582,8 +582,7 @@ <h4>testclasses</h4>
582582

583583
<p>
584584
The <a href="#fork">fork</a> nested element can be used to run the tests in a newly forked
585-
JVM. All tests that are part of this <code>testclasses</code> element will run in one single
586-
instance of the newly forked JVM.
585+
JVM.
587586
</p>
588587

589588
<h4 id="fork">fork</h4>
@@ -613,6 +612,17 @@ <h4 id="fork">fork</h4>
613612
than this configured value, then the JVM is killed</td>
614613
<td>No</td>
615614
</tr>
615+
<tr>
616+
<td>mode</td>
617+
<td>Controls how many JVMs get created if you want to fork some tests. Possible values
618+
are <q>once</q> (the default) and <q>perTest</q>. <q>once</q> creates only a single
619+
JVM for all tests while <q>perTest</q> creates a new JVM for each test suite class.
620+
Note that only tests within the same <q>fork</q> element can share a JVM, so even
621+
if you set <var>mode</var> to <q>once</q> Ant may have to create more than one JVM.
622+
<p><em>Since Ant 1.10.13</em></p>
623+
</td>
624+
<td>No; defaults to <q>once</q></td>
625+
</tr>
616626
<tr>
617627
<td>includeJUnitPlatformLibraries</td>
618628
<td>If set to <code>true</code>, then the jar files that make up the

src/etc/testcases/taskdefs/optional/junitlauncher.xml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,29 @@
166166
</junitlauncher>
167167
</target>
168168

169+
<target name="test-per-test-fork-mode" depends="init">
170+
<junitlauncher>
171+
<classpath refid="test.classpath"/>
172+
<testclasses outputdir="${output.dir}">
173+
<!-- the same test is duplicated intentionally; if both are run in the same JVM the second one will
174+
fail, it is a nice way to ensure "perTest" mode runs every test suite class in a separate JVM -->
175+
<fileset dir="${build.classes.dir}" includes="org/example/**/junitlauncher/**/ForkedTest.class"/>
176+
<fileset dir="${build.classes.dir}" includes="org/example/**/junitlauncher/**/ForkedTest.class"/>
177+
178+
<listener classname="org.example.junitlauncher.Tracker"
179+
outputDir="${output.dir}"
180+
resultFile="${test-per-test-fork-mode.tracker}"
181+
if="test-per-test-fork-mode.tracker"/>
182+
183+
<fork dir="${basedir}" mode="perTest">
184+
<sysproperty key="junitlauncher.test.sysprop.one" value="forked"/>
185+
</fork>
186+
187+
<listener type="legacy-xml" sendSysErr="true" sendSysOut="true" useLegacyReportingName="false"/>
188+
</testclasses>
189+
</junitlauncher>
190+
</target>
191+
169192
<target name="test-junit-platform-lib-excluded" depends="init">
170193
<junitlauncher>
171194
<classpath refid="junit.engine.jupiter.classpath"/>

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/ForkDefinition.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.tools.ant.Project;
2323
import org.apache.tools.ant.types.Commandline;
2424
import org.apache.tools.ant.types.CommandlineJava;
25+
import org.apache.tools.ant.types.EnumeratedAttribute;
2526
import org.apache.tools.ant.types.Environment;
2627
import org.apache.tools.ant.types.Path;
2728
import org.apache.tools.ant.types.PropertySet;
@@ -42,6 +43,7 @@ public class ForkDefinition {
4243

4344
private String dir;
4445
private long timeout = -1;
46+
private Mode mode = new Mode("once");
4547

4648
ForkDefinition() {
4749
this.commandLineJava = new CommandlineJava();
@@ -63,14 +65,37 @@ long getTimeout() {
6365
return this.timeout;
6466
}
6567

68+
/**
69+
* Possible values are "once" and "perTest". If set to "once" (the default),
70+
* only a single Java VM will be forked for all tests, with "perTest" each test
71+
* will be run in a fresh Java VM.
72+
* @param mode the mode to use.
73+
* @since Ant 1.10.13
74+
*/
75+
public void setMode(final Mode mode) {
76+
this.mode = mode;
77+
}
78+
79+
public Mode getMode() {
80+
return mode;
81+
}
82+
6683
public void setIncludeJUnitPlatformLibraries(final boolean include) {
6784
this.includeJUnitPlatformLibraries = include;
6885
}
6986

87+
public boolean isIncludeJUnitPlatformLibraries() {
88+
return includeJUnitPlatformLibraries;
89+
}
90+
7091
public void setIncludeAntRuntimeLibraries(final boolean include) {
7192
this.includeAntRuntimeLibraries = include;
7293
}
7394

95+
public boolean isIncludeAntRuntimeLibraries() {
96+
return includeAntRuntimeLibraries;
97+
}
98+
7499
public Commandline.Argument createJvmArg() {
75100
return this.commandLineJava.createVmArgument();
76101
}
@@ -140,4 +165,39 @@ CommandlineJava generateCommandLine(final JUnitLauncherTask task) {
140165
return cmdLine;
141166
}
142167

168+
/**
169+
* Forking option. There are two available: "once" and "perTest".
170+
* @since Ant 1.10.13
171+
*/
172+
public static final class Mode extends EnumeratedAttribute {
173+
174+
/**
175+
* fork once only
176+
*/
177+
public static final String ONCE = "once";
178+
/**
179+
* fork once per test class
180+
*/
181+
public static final String PER_TEST = "perTest";
182+
183+
/** No arg constructor. */
184+
public Mode() {
185+
super();
186+
}
187+
188+
/**
189+
* Constructor using a value.
190+
* @param value the value to use - once or perTest.
191+
*/
192+
public Mode(final String value) {
193+
super();
194+
setValue(value);
195+
}
196+
197+
/** {@inheritDoc}. */
198+
@Override
199+
public String[] getValues() {
200+
return new String[] {ONCE, PER_TEST};
201+
}
202+
}
143203
}

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/JUnitLauncherTask.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,41 @@ public void execute() throws BuildException {
100100
continue;
101101
}
102102
if (test.getForkDefinition() != null) {
103-
forkTest(test);
103+
if (test instanceof TestClasses
104+
&& test.getForkDefinition().getMode().getValue().equals(ForkDefinition.Mode.PER_TEST)) {
105+
TestClasses testClasses = (TestClasses) test;
106+
for (String testClassName : testClasses.getTestClassNames()) {
107+
forkTest(convertToSingleTestClass(testClasses, testClassName));
108+
}
109+
} else {
110+
forkTest(test);
111+
}
104112
} else {
105113
launchViaReflection(new InVMLaunch(Collections.singletonList(test)));
106114
}
107115
}
108116
}
109117

118+
private SingleTestClass convertToSingleTestClass(TestClasses testClasses, String testClassName) {
119+
SingleTestClass singleTestClass = new SingleTestClass();
120+
singleTestClass.setName(testClassName);
121+
singleTestClass.setIf(testClasses.ifProperty);
122+
singleTestClass.setUnless(testClasses.unlessProperty);
123+
singleTestClass.setHaltOnFailure(testClasses.haltOnFailure);
124+
singleTestClass.setFailureProperty(testClasses.failureProperty);
125+
singleTestClass.setOutputDir(testClasses.outputDir);
126+
singleTestClass.setIncludeEngines(testClasses.includeEngines);
127+
singleTestClass.setExcludeEngines(testClasses.excludeEngines);
128+
129+
for (ListenerDefinition listener : testClasses.getListeners()) {
130+
singleTestClass.addConfiguredListener(listener);
131+
}
132+
133+
singleTestClass.setForkDefinition(testClasses.getForkDefinition());
134+
135+
return singleTestClass;
136+
}
137+
110138
/**
111139
* Adds the {@link Path} to the classpath which will be used for execution of the tests
112140
*

src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/confined/TestDefinition.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ ForkDefinition getForkDefinition() {
107107
return this.forkDefinition;
108108
}
109109

110+
public void setForkDefinition(ForkDefinition forkDefinition) {
111+
this.forkDefinition = forkDefinition;
112+
}
113+
110114
protected boolean shouldRun(final Project project) {
111115
final PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(project);
112116
return propertyHelper.testIfCondition(this.ifProperty) && propertyHelper.testUnlessCondition(this.unlessProperty);

src/tests/junit/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTaskTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,26 @@ public void testBasicFork() throws Exception {
209209
ForkedTest.class.getName(), "testSysProp"));
210210
}
211211

212+
/**
213+
* Tests the execution of a forked test with "perTest" mode
214+
*/
215+
@Test
216+
public void testPerTestForkMode() throws Exception {
217+
final String targetName = "test-per-test-fork-mode";
218+
final Path trackerFile = setupTrackerProperty(targetName);
219+
// setup a dummy and incorrect value of a sysproperty that's used in the test being forked
220+
System.setProperty(ForkedTest.SYS_PROP_ONE, "dummy");
221+
buildRule.executeTarget(targetName);
222+
// verify that our JVM's sysprop value didn't get changed
223+
Assert.assertEquals("System property " + ForkedTest.SYS_PROP_ONE + " was unexpected updated",
224+
"dummy", System.getProperty(ForkedTest.SYS_PROP_ONE));
225+
226+
Assert.assertTrue("At least one run of ForkedTest#testSysProp was expected to succeed",
227+
verifySuccess(trackerFile, ForkedTest.class.getName(), "testSysProp"));
228+
Assert.assertFalse("No runs of ForkedTest#testSysProp was expected to fail",
229+
verifyFailed(trackerFile, ForkedTest.class.getName(), "testSysProp"));
230+
}
231+
212232
/**
213233
* Tests that in a forked mode execution of tests, when the {@code includeJUnitPlatformLibraries} attribute
214234
* is set to false, then the execution of such tests fails with a classloading error for the JUnit platform

src/tests/junit/org/example/junitlauncher/vintage/ForkedTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@ public class ForkedTest {
3333
public void testSysProp() {
3434
Assert.assertEquals("Unexpected value for system property",
3535
"forked", System.getProperty(SYS_PROP_ONE));
36+
System.setProperty(SYS_PROP_ONE, "changed_inside_fork");
3637
}
3738
}

0 commit comments

Comments
 (0)