Skip to content

Commit adf6d43

Browse files
committed
Log all discovered configuration files to assist in problem resolution
Resolves #3898.
1 parent 0ca1754 commit adf6d43

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

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

+15-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

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

13+
import static java.util.stream.Collectors.joining;
14+
1315
import java.io.InputStream;
1416
import java.net.URL;
1517
import java.net.URLConnection;
@@ -25,6 +27,7 @@
2527
import java.util.Properties;
2628
import java.util.Set;
2729
import java.util.stream.Collectors;
30+
import java.util.stream.Stream;
2831

2932
import org.junit.platform.commons.logging.Logger;
3033
import org.junit.platform.commons.logging.LoggerFactory;
@@ -272,13 +275,21 @@ private static Properties loadClasspathResource(String configFileName) {
272275
Set<URL> resources = new LinkedHashSet<>(Collections.list(classLoader.getResources(configFileName)));
273276

274277
if (!resources.isEmpty()) {
278+
279+
URL configFileUrl = CollectionUtils.getFirstElement(resources).get();
280+
275281
if (resources.size() > 1) {
276-
logger.warn(() -> String.format(
277-
"Discovered %d '%s' configuration files in the classpath; only the first will be used.",
278-
resources.size(), configFileName));
282+
logger.warn(() -> {
283+
String formattedResourceList = Stream.concat( //
284+
Stream.of(configFileUrl + " (*)"), //
285+
resources.stream().skip(1).map(URL::toString) //
286+
).collect(joining("\n- ", "\n- ", ""));
287+
return String.format(
288+
"Discovered %d '%s' configuration files on the classpath (see below); only the first (*) will be used.%s",
289+
resources.size(), configFileName, formattedResourceList);
290+
});
279291
}
280292

281-
URL configFileUrl = resources.iterator().next(); // same as List#get(0)
282293
logger.config(() -> String.format(
283294
"Loading JUnit Platform configuration parameters from classpath resource [%s].", configFileUrl));
284295
URLConnection urlConnection = configFileUrl.openConnection();

platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherConfigurationParametersTests.java

+45
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,27 @@
1414
import static org.junit.jupiter.api.Assertions.assertEquals;
1515
import static org.junit.jupiter.api.Assertions.assertThrows;
1616

17+
import java.net.URL;
18+
import java.net.URLClassLoader;
19+
import java.nio.file.Files;
20+
import java.nio.file.Path;
21+
import java.util.List;
1722
import java.util.Map;
23+
import java.util.Properties;
24+
import java.util.logging.Level;
25+
import java.util.logging.LogRecord;
1826

1927
import org.junit.jupiter.api.AfterEach;
2028
import org.junit.jupiter.api.BeforeEach;
2129
import org.junit.jupiter.api.Test;
2230
import org.junit.jupiter.api.extension.ExtendWith;
2331
import org.junit.jupiter.api.extension.ExtensionContext;
2432
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
33+
import org.junit.jupiter.api.fixtures.TrackLogRecords;
34+
import org.junit.jupiter.api.io.TempDir;
2535
import org.junit.platform.commons.JUnitException;
2636
import org.junit.platform.commons.PreconditionViolationException;
37+
import org.junit.platform.commons.logging.LogRecordListener;
2738
import org.junit.platform.engine.ConfigurationParameters;
2839
import org.junit.platform.engine.discovery.DiscoverySelectors;
2940
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
@@ -190,6 +201,40 @@ void ignoresSystemPropertyAndConfigFileWhenImplicitLookupsAreDisabled() {
190201
assertThat(configParams.get(KEY)).isEmpty();
191202
}
192203

204+
@Test
205+
void warnsOnMultiplePropertyResources(@TempDir Path tempDir, @TrackLogRecords LogRecordListener logRecordListener)
206+
throws Exception {
207+
Properties properties = new Properties();
208+
properties.setProperty(KEY, "from second config file");
209+
try (var out = Files.newOutputStream(tempDir.resolve(CONFIG_FILE_NAME))) {
210+
properties.store(out, "");
211+
}
212+
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
213+
try (var customClassLoader = new URLClassLoader(new URL[] { tempDir.toUri().toURL() }, originalClassLoader)) {
214+
Thread.currentThread().setContextClassLoader(customClassLoader);
215+
ConfigurationParameters configParams = fromMapAndFile(Map.of(), CONFIG_FILE_NAME);
216+
217+
assertThat(configParams.get(KEY)).contains(CONFIG_FILE);
218+
219+
List<String> loggedWarnings = logRecordListener.stream(Level.WARNING) //
220+
.map(LogRecord::getMessage) //
221+
.toList();
222+
assertThat(loggedWarnings) //
223+
.hasSize(1);
224+
assertThat(loggedWarnings.getFirst()) //
225+
.contains("Discovered 2 '" + CONFIG_FILE_NAME
226+
+ "' configuration files on the classpath (see below); only the first (*) will be used.") //
227+
.contains("- "
228+
+ Path.of(
229+
"build/resources/test/test-junit-platform.properties").toAbsolutePath().toUri().toURL()
230+
+ " (*)") //
231+
.contains("- " + tempDir.resolve(CONFIG_FILE_NAME).toUri().toURL());
232+
}
233+
finally {
234+
Thread.currentThread().setContextClassLoader(originalClassLoader);
235+
}
236+
}
237+
193238
private static LauncherConfigurationParameters fromMap(Map<String, String> map) {
194239
return LauncherConfigurationParameters.builder().explicitParameters(map).build();
195240
}

0 commit comments

Comments
 (0)