Skip to content

Commit 66463b8

Browse files
committed
Use ConsoleLauncher's --reports-dir as report output dir
Moreover, when an output dir is configured explicitly it's now used without creating another subdirectory. A new `{uniqueNumber}` placeholder may be used to create a unique directory per test execution. This may be used by build tools that create multiple forks to run tests in parallel.
1 parent d9215bf commit 66463b8

File tree

15 files changed

+91
-77
lines changed

15 files changed

+91
-77
lines changed

documentation/documentation.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ tasks {
147147

148148
val consoleLauncherTestReportsDir = project.layout.buildDirectory.dir("console-launcher-test-results")
149149
val consoleLauncherTestEventXmlFiles =
150-
files(consoleLauncherTestReportsDir.map { it.asFileTree.matching { include("junit-*/open-test-report.xml") } })
150+
files(consoleLauncherTestReportsDir.map { it.asFileTree.matching { include("**/open-test-report.xml") } })
151151

152152
val consoleLauncherTest by registering(RunConsoleLauncher::class) {
153153
args.addAll("execute")
@@ -157,7 +157,6 @@ tasks {
157157
argumentProviders.add(CommandLineArgumentProvider {
158158
listOf(
159159
"--reports-dir=${consoleLauncherTestReportsDir.get()}",
160-
"--config=junit.platform.reporting.output.dir=${consoleLauncherTestReportsDir.get()}",
161160
)
162161
})
163162
args.addAll("--include-classname", ".*Tests")

gradle/plugins/common/src/main/kotlin/junitbuild.testing-conventions.gradle.kts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import org.gradle.api.tasks.PathSensitivity.NONE
55
import org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
66
import org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED
77
import org.gradle.internal.os.OperatingSystem
8-
import java.nio.file.Files
98

109
plugins {
1110
`java-library`
@@ -113,14 +112,16 @@ tasks.withType<Test>().configureEach {
113112
jvmArgumentProviders += CommandLineArgumentProvider {
114113
listOf(
115114
"-Djunit.platform.reporting.open.xml.enabled=true",
116-
"-Djunit.platform.reporting.output.dir=${reports.junitXml.outputLocation.get().asFile.absolutePath}"
115+
"-Djunit.platform.reporting.output.dir=${reports.junitXml.outputLocation.get().asFile.absolutePath}/junit-{uniqueNumber}",
117116
)
118117
}
119118

120-
val reportFiles = objects.fileTree().from(reports.junitXml.outputLocation).matching { include("junit-*/open-test-report.xml") }
119+
val reportDirTree = objects.fileTree().from(reports.junitXml.outputLocation)
121120
doFirst {
122-
reportFiles.files.forEach {
123-
Files.delete(it.toPath())
121+
reportDirTree.visit {
122+
if (name.startsWith("junit-")) {
123+
file.deleteRecursively()
124+
}
124125
}
125126
}
126127

junit-platform-console/src/main/java/org/junit/platform/console/tasks/ConsoleTestExecutor.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
package org.junit.platform.console.tasks;
1212

1313
import static org.apiguardian.api.API.Status.INTERNAL;
14+
import static org.junit.platform.console.tasks.DiscoveryRequestCreator.toDiscoveryRequestBuilder;
15+
import static org.junit.platform.launcher.LauncherConstants.OUTPUT_DIR_PROPERTY_NAME;
1416

1517
import java.io.PrintWriter;
1618
import java.net.URL;
@@ -32,6 +34,7 @@
3234
import org.junit.platform.launcher.LauncherDiscoveryRequest;
3335
import org.junit.platform.launcher.TestExecutionListener;
3436
import org.junit.platform.launcher.TestPlan;
37+
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
3538
import org.junit.platform.launcher.core.LauncherFactory;
3639
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
3740
import org.junit.platform.launcher.listeners.TestExecutionSummary;
@@ -75,7 +78,7 @@ private void discoverTests(PrintWriter out) {
7578
Launcher launcher = launcherSupplier.get();
7679
Optional<DetailsPrintingListener> commandLineTestPrinter = createDetailsPrintingListener(out);
7780

78-
LauncherDiscoveryRequest discoveryRequest = new DiscoveryRequestCreator().toDiscoveryRequest(discoveryOptions);
81+
LauncherDiscoveryRequest discoveryRequest = toDiscoveryRequestBuilder(discoveryOptions).build();
7982
TestPlan testPlan = launcher.discover(discoveryRequest);
8083

8184
commandLineTestPrinter.ifPresent(printer -> printer.listTests(testPlan));
@@ -98,8 +101,10 @@ private TestExecutionSummary executeTests(PrintWriter out, Optional<Path> report
98101
Launcher launcher = launcherSupplier.get();
99102
SummaryGeneratingListener summaryListener = registerListeners(out, reportsDir, launcher);
100103

101-
LauncherDiscoveryRequest discoveryRequest = new DiscoveryRequestCreator().toDiscoveryRequest(discoveryOptions);
102-
launcher.execute(discoveryRequest);
104+
LauncherDiscoveryRequestBuilder discoveryRequestBuilder = toDiscoveryRequestBuilder(discoveryOptions);
105+
reportsDir.ifPresent(dir -> discoveryRequestBuilder.configurationParameter(OUTPUT_DIR_PROPERTY_NAME,
106+
dir.toAbsolutePath().toString()));
107+
launcher.execute(discoveryRequestBuilder.build());
103108

104109
TestExecutionSummary summary = summaryListener.getSummary();
105110
if (summary.getTotalFailureCount() > 0 || outputOptions.getDetails() != Details.NONE) {

junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,25 @@
4242
import org.junit.platform.engine.discovery.ClasspathRootSelector;
4343
import org.junit.platform.engine.discovery.IterationSelector;
4444
import org.junit.platform.engine.discovery.MethodSelector;
45-
import org.junit.platform.launcher.LauncherDiscoveryRequest;
4645
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
4746

4847
/**
4948
* @since 1.0
5049
*/
5150
class DiscoveryRequestCreator {
5251

53-
LauncherDiscoveryRequest toDiscoveryRequest(TestDiscoveryOptions options) {
52+
static LauncherDiscoveryRequestBuilder toDiscoveryRequestBuilder(TestDiscoveryOptions options) {
5453
LauncherDiscoveryRequestBuilder requestBuilder = request();
5554
List<? extends DiscoverySelector> selectors = createDiscoverySelectors(options);
5655
requestBuilder.selectors(selectors);
5756
addFilters(requestBuilder, options, selectors);
5857
requestBuilder.configurationParameters(options.getConfigurationParameters());
5958
requestBuilder.configurationParametersResources(
6059
options.getConfigurationParametersResources().toArray(new String[0]));
61-
return requestBuilder.build();
60+
return requestBuilder;
6261
}
6362

64-
private List<? extends DiscoverySelector> createDiscoverySelectors(TestDiscoveryOptions options) {
63+
private static List<? extends DiscoverySelector> createDiscoverySelectors(TestDiscoveryOptions options) {
6564
List<DiscoverySelector> explicitSelectors = options.getExplicitSelectors();
6665
if (options.isScanClasspath()) {
6766
Preconditions.condition(explicitSelectors.isEmpty(),
@@ -77,12 +76,12 @@ private List<? extends DiscoverySelector> createDiscoverySelectors(TestDiscovery
7776
"Please specify an explicit selector option or use --scan-class-path or --scan-modules");
7877
}
7978

80-
private List<ClasspathRootSelector> createClasspathRootSelectors(TestDiscoveryOptions options) {
79+
private static List<ClasspathRootSelector> createClasspathRootSelectors(TestDiscoveryOptions options) {
8180
Set<Path> classpathRoots = determineClasspathRoots(options);
8281
return selectClasspathRoots(classpathRoots);
8382
}
8483

85-
private Set<Path> determineClasspathRoots(TestDiscoveryOptions options) {
84+
private static Set<Path> determineClasspathRoots(TestDiscoveryOptions options) {
8685
if (options.getSelectedClasspathEntries().isEmpty()) {
8786
Set<Path> rootDirs = new LinkedHashSet<>(ReflectionUtils.getAllClasspathRootDirectories());
8887
rootDirs.addAll(options.getExistingAdditionalClasspathEntries());
@@ -91,7 +90,7 @@ private Set<Path> determineClasspathRoots(TestDiscoveryOptions options) {
9190
return new LinkedHashSet<>(options.getSelectedClasspathEntries());
9291
}
9392

94-
private void addFilters(LauncherDiscoveryRequestBuilder requestBuilder, TestDiscoveryOptions options,
93+
private static void addFilters(LauncherDiscoveryRequestBuilder requestBuilder, TestDiscoveryOptions options,
9594
List<? extends DiscoverySelector> selectors) {
9695
requestBuilder.filters(includedClassNamePatterns(options, selectors));
9796

@@ -133,7 +132,7 @@ private void addFilters(LauncherDiscoveryRequestBuilder requestBuilder, TestDisc
133132
}
134133
}
135134

136-
private ClassNameFilter includedClassNamePatterns(TestDiscoveryOptions options,
135+
private static ClassNameFilter includedClassNamePatterns(TestDiscoveryOptions options,
137136
List<? extends DiscoverySelector> selectors) {
138137
Stream<String> patternStreams = Stream.concat( //
139138
options.getIncludedClassNamePatterns().stream(), //

junit-platform-launcher/src/main/java/org/junit/platform/launcher/LauncherConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ public class LauncherConstants {
193193

194194
public static final String OUTPUT_DIR_PROPERTY_NAME = "junit.platform.reporting.output.dir";
195195

196+
public static final String OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER = "{uniqueNumber}";
197+
196198
private LauncherConstants() {
197199
/* no-op */
198200
}

junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,10 +327,8 @@ private OutputDirectoryProvider getOutputDirectoryProvider(
327327
if (this.outputDirectoryProvider != null) {
328328
return this.outputDirectoryProvider;
329329
}
330-
return new HierarchicalOutputDirectoryProvider(() -> {
331-
OutputDir outputDir = OutputDir.create(configurationParameters.get(OUTPUT_DIR_PROPERTY_NAME));
332-
return outputDir.createDir("junit");
333-
});
330+
return new HierarchicalOutputDirectoryProvider(
331+
() -> OutputDir.create(configurationParameters.get(OUTPUT_DIR_PROPERTY_NAME)).toPath());
334332
}
335333

336334
private LauncherConfigurationParameters buildLauncherConfigurationParameters() {

junit-platform-launcher/src/main/java/org/junit/platform/launcher/listeners/OutputDir.java

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
package org.junit.platform.launcher.listeners;
1212

1313
import static org.apiguardian.api.API.Status.INTERNAL;
14+
import static org.junit.platform.launcher.LauncherConstants.OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER;
1415

1516
import java.io.IOException;
1617
import java.io.UncheckedIOException;
@@ -22,6 +23,7 @@
2223
import java.util.Optional;
2324
import java.util.function.BiPredicate;
2425
import java.util.function.Supplier;
26+
import java.util.regex.Pattern;
2527
import java.util.stream.Stream;
2628

2729
import org.apiguardian.api.API;
@@ -30,13 +32,10 @@
3032
@API(status = INTERNAL, since = "1.9")
3133
public class OutputDir {
3234

33-
private final SecureRandom random = new SecureRandom();
35+
private static final Pattern OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER_PATTERN = Pattern.compile(
36+
Pattern.quote(OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER));
3437

3538
public static OutputDir create(Optional<String> customDir) {
36-
return createWithPath(customDir.filter(StringUtils::isNotBlank).map(Paths::get));
37-
}
38-
39-
public static OutputDir createWithPath(Optional<Path> customDir) {
4039
try {
4140
return createSafely(customDir, () -> Paths.get(".").toAbsolutePath());
4241
}
@@ -48,12 +47,22 @@ public static OutputDir createWithPath(Optional<Path> customDir) {
4847
/**
4948
* Package private for testing purposes.
5049
*/
51-
static OutputDir createSafely(Optional<Path> customDir, Supplier<Path> currentWorkingDir) throws IOException {
50+
static OutputDir createSafely(Optional<String> customDir, Supplier<Path> currentWorkingDir) throws IOException {
51+
return createSafely(customDir, currentWorkingDir, new SecureRandom());
52+
}
53+
54+
private static OutputDir createSafely(Optional<String> customDir, Supplier<Path> currentWorkingDir,
55+
SecureRandom random) throws IOException {
5256
Path cwd = currentWorkingDir.get();
5357
Path outputDir;
5458

55-
if (customDir.isPresent()) {
56-
outputDir = cwd.resolve(customDir.get());
59+
if (customDir.isPresent() && StringUtils.isNotBlank(customDir.get())) {
60+
String customPath = customDir.get();
61+
while (customPath.contains(OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER)) {
62+
customPath = OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER_PATTERN.matcher(customPath) //
63+
.replaceFirst(String.valueOf(Math.abs(random.nextLong())));
64+
}
65+
outputDir = cwd.resolve(customPath);
5766
}
5867
else if (Files.exists(cwd.resolve("pom.xml"))) {
5968
outputDir = cwd.resolve("target");
@@ -69,31 +78,21 @@ else if (containsFilesWithExtensions(cwd, ".gradle", ".gradle.kts")) {
6978
Files.createDirectories(outputDir);
7079
}
7180

72-
return new OutputDir(outputDir.normalize());
81+
return new OutputDir(outputDir.normalize(), random);
7382
}
7483

7584
private final Path path;
85+
private final SecureRandom random;
7686

77-
private OutputDir(Path path) {
87+
private OutputDir(Path path, SecureRandom random) {
7888
this.path = path;
89+
this.random = random;
7990
}
8091

8192
public Path toPath() {
8293
return path;
8394
}
8495

85-
public Path createDir(String prefix) throws UncheckedIOException {
86-
String filename = String.format("%s-%d", prefix, Math.abs(random.nextLong()));
87-
Path outputFile = path.resolve(filename);
88-
89-
try {
90-
return Files.createDirectory(outputFile);
91-
}
92-
catch (IOException e) {
93-
throw new UncheckedIOException("Failed to create output directory: " + outputFile, e);
94-
}
95-
}
96-
9796
public Path createFile(String prefix, String extension) throws UncheckedIOException {
9897
String filename = String.format("%s-%d.%s", prefix, Math.abs(random.nextLong()), extension);
9998
Path outputFile = path.resolve(filename);

platform-tests/src/test/java/org/junit/platform/console/tasks/DiscoveryRequestCreatorTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,7 @@ void convertsConfigurationParametersResources() {
359359
}
360360

361361
private LauncherDiscoveryRequest convert() {
362-
var creator = new DiscoveryRequestCreator();
363-
return creator.toDiscoveryRequest(options);
362+
return DiscoveryRequestCreator.toDiscoveryRequestBuilder(options).build();
364363
}
365364

366365
private void assertIncludes(Filter<String> filter, String included) {

platform-tests/src/test/java/org/junit/platform/launcher/listeners/OutputDirTests.java

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,77 +10,92 @@
1010

1111
package org.junit.platform.launcher.listeners;
1212

13+
import static org.assertj.core.api.Assertions.as;
1314
import static org.assertj.core.api.Assertions.assertThat;
15+
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
1416

1517
import java.io.IOException;
1618
import java.nio.file.Files;
1719
import java.nio.file.Path;
18-
import java.nio.file.Paths;
1920
import java.util.Optional;
2021

2122
import org.junit.jupiter.api.Test;
23+
import org.junit.jupiter.api.io.TempDir;
24+
import org.junit.platform.launcher.LauncherConstants;
2225

2326
class OutputDirTests {
2427

28+
@TempDir
29+
Path cwd;
30+
2531
@Test
2632
void getOutputDirUsesCustomOutputDir() throws Exception {
27-
String customDir = "build/UniqueIdTrackingListenerIntegrationTests";
28-
Path outputDir = OutputDir.create(Optional.of(customDir)).toPath();
29-
assertThat(Files.isSameFile(Paths.get(customDir), outputDir)).isTrue();
33+
var customDir = cwd.resolve("custom-dir");
34+
var outputDir = OutputDir.create(Optional.of(customDir.toAbsolutePath().toString())).toPath();
35+
assertThat(Files.isSameFile(customDir, outputDir)).isTrue();
3036
assertThat(outputDir).exists();
3137
}
3238

39+
@Test
40+
void getOutputDirUsesCustomOutputDirWithPlaceholder() {
41+
var customDir = cwd.resolve("build").resolve("junit-" + LauncherConstants.OUTPUT_DIR_UNIQUE_NUMBER_PLACEHOLDER);
42+
var outputDir = OutputDir.create(Optional.of(customDir.toAbsolutePath().toString())).toPath();
43+
assertThat(outputDir).exists() //
44+
.hasParent(cwd.resolve("build")) //
45+
.extracting(it -> it.getFileName().toString(), as(STRING)) //
46+
.matches("junit-\\d+");
47+
}
48+
3349
@Test
3450
void getOutputDirFallsBackToCurrentWorkingDir() throws Exception {
35-
String cwd = "src/test/resources/listeners/uidtracking";
36-
String expected = cwd;
51+
var expected = cwd;
3752

38-
assertOutputDirIsDetected(cwd, expected);
53+
assertOutputDirIsDetected(expected);
3954
}
4055

4156
@Test
4257
void getOutputDirDetectsMavenPom() throws Exception {
43-
String cwd = "src/test/resources/listeners/uidtracking/maven";
44-
String expected = cwd + "/target";
58+
Files.createFile(cwd.resolve("pom.xml"));
59+
var expected = cwd.resolve("target");
4560

46-
assertOutputDirIsDetected(cwd, expected);
61+
assertOutputDirIsDetected(expected);
4762
}
4863

4964
@Test
5065
void getOutputDirDetectsGradleGroovyDefaultBuildScript() throws Exception {
51-
String cwd = "src/test/resources/listeners/uidtracking/gradle/groovy";
52-
String expected = cwd + "/build";
66+
Files.createFile(cwd.resolve("build.gradle"));
67+
var expected = cwd.resolve("build");
5368

54-
assertOutputDirIsDetected(cwd, expected);
69+
assertOutputDirIsDetected(expected);
5570
}
5671

5772
@Test
5873
void getOutputDirDetectsGradleGroovyCustomBuildScript() throws Exception {
59-
String cwd = "src/test/resources/listeners/uidtracking/gradle/groovy/sub-project";
60-
String expected = cwd + "/build";
74+
Files.createFile(cwd.resolve("sub-project.gradle"));
75+
var expected = cwd.resolve("build");
6176

62-
assertOutputDirIsDetected(cwd, expected);
77+
assertOutputDirIsDetected(expected);
6378
}
6479

6580
@Test
6681
void getOutputDirDetectsGradleKotlinDefaultBuildScript() throws Exception {
67-
String cwd = "src/test/resources/listeners/uidtracking/gradle/kotlin";
68-
String expected = cwd + "/build";
82+
Files.createFile(cwd.resolve("build.gradle.kts"));
83+
var expected = cwd.resolve("build");
6984

70-
assertOutputDirIsDetected(cwd, expected);
85+
assertOutputDirIsDetected(expected);
7186
}
7287

7388
@Test
7489
void getOutputDirDetectsGradleKotlinCustomBuildScript() throws Exception {
75-
String cwd = "src/test/resources/listeners/uidtracking/gradle/kotlin/sub-project";
76-
String expected = cwd + "/build";
90+
Files.createFile(cwd.resolve("sub-project.gradle.kts"));
91+
var expected = cwd.resolve("build");
7792

78-
assertOutputDirIsDetected(cwd, expected);
93+
assertOutputDirIsDetected(expected);
7994
}
8095

81-
private void assertOutputDirIsDetected(String cwd, String expected) throws IOException {
82-
Path outputDir = OutputDir.createSafely(Optional.empty(), () -> Paths.get(cwd)).toPath();
83-
assertThat(Files.isSameFile(Paths.get(expected), outputDir)).isTrue();
96+
private void assertOutputDirIsDetected(Path expected) throws IOException {
97+
var outputDir = OutputDir.createSafely(Optional.empty(), () -> cwd).toPath();
98+
assertThat(Files.isSameFile(expected, outputDir)).isTrue();
8499
assertThat(outputDir).exists();
85100
}
86101

0 commit comments

Comments
 (0)