From fd45908d5d3cdd9ee79e36ccdef9ab708b863a22 Mon Sep 17 00:00:00 2001 From: Robin Jonsson Hector Date: Thu, 8 Jun 2023 14:07:35 +0200 Subject: [PATCH] Add support for configuration parameters resources This commit adds support for specifying a properties file, for use with configuration parameters. - Added a new field configurationParametersResources of type List to store the configuration parameters resources. - Added new methods configurationParametersResource(String propertiesFile) and configurationParametersResources(List propertiesFiles) to add configuration parameters resources to the request builder. - Updated the buildLauncherConfigurationParameters() method to include the configurationParametersResources in the Builder instance. Related to issue: #3340 --- .../asciidoc/user-guide/running-tests.adoc | 9 ++-- .../console/options/TestDiscoveryOptions.java | 9 ++++ .../tasks/DiscoveryRequestCreator.java | 1 + .../core/LauncherConfigurationParameters.java | 11 ++++ .../core/LauncherDiscoveryRequestBuilder.java | 26 ++++++++++ .../junit/platform/runner/JUnitPlatform.java | 2 + .../api/ConfigurationParametersResource.java | 51 +++++++++++++++++++ .../api/ConfigurationParametersResources.java | 50 ++++++++++++++++++ .../SuiteLauncherDiscoveryRequestBuilder.java | 8 +++ .../LauncherDiscoveryRequestBuilderTests.java | 42 +++++++++++++++ ...eLauncherDiscoveryRequestBuilderTests.java | 44 ++++++++++++++++ .../resources/config-test-override.properties | 2 + .../src/test/resources/config-test.properties | 4 ++ 13 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResource.java create mode 100644 junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResources.java create mode 100644 platform-tests/src/test/resources/config-test-override.properties create mode 100644 platform-tests/src/test/resources/config-test.properties diff --git a/documentation/src/docs/asciidoc/user-guide/running-tests.adoc b/documentation/src/docs/asciidoc/user-guide/running-tests.adoc index 8461b9bc7c1f..257ad3bc9983 100644 --- a/documentation/src/docs/asciidoc/user-guide/running-tests.adoc +++ b/documentation/src/docs/asciidoc/user-guide/running-tests.adoc @@ -895,13 +895,16 @@ engines running on the JUnit Platform via one of the following mechanisms. `systemProperty` or `systemProperties` DSL. * <>: use the `configurationParameters` property. -2. JVM system properties. -3. The JUnit Platform configuration file: a file named `junit-platform.properties` in the +2. The `configurationParametersResource()` and `configurationParametersResources()` + methods in the `LauncherDiscoveryRequestBuilder` which are used to select a `.properties` + file on the classpath with configuration parameters. +3. JVM system properties. +4. The JUnit Platform configuration file: a file named `junit-platform.properties` in the root of the class path that follows the syntax rules for a Java `Properties` file. NOTE: Configuration parameters are looked up in the exact order defined above. Consequently, configuration parameters supplied directly to the `Launcher` take -precedence over those supplied via system properties and the configuration file. +precedence over those supplied via system properties, the specified properties files, and the platform configuration file. Similarly, configuration parameters supplied via system properties take precedence over those supplied via the configuration file. diff --git a/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptions.java b/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptions.java index b7949de159f6..793c1a08b2a2 100644 --- a/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptions.java +++ b/junit-platform-console/src/main/java/org/junit/platform/console/options/TestDiscoveryOptions.java @@ -66,6 +66,7 @@ public class TestDiscoveryOptions { private List includedTagExpressions = emptyList(); private List excludedTagExpressions = emptyList(); + private List configurationParametersResources = emptyList(); private Map configurationParameters = emptyMap(); public boolean isScanModulepath() { @@ -262,4 +263,12 @@ public void setConfigurationParameters(Map configurationParamete this.configurationParameters = configurationParameters; } + public List getConfigurationParametersResources() { + return configurationParametersResources; + } + + public TestDiscoveryOptions setConfigurationParametersResources(List configurationParametersResources) { + this.configurationParametersResources = configurationParametersResources; + return this; + } } diff --git a/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java b/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java index 89aeec8c3817..3f35e778c1bf 100644 --- a/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java +++ b/junit-platform-console/src/main/java/org/junit/platform/console/tasks/DiscoveryRequestCreator.java @@ -54,6 +54,7 @@ LauncherDiscoveryRequest toDiscoveryRequest(TestDiscoveryOptions options) { requestBuilder.selectors(selectors); addFilters(requestBuilder, options, selectors); requestBuilder.configurationParameters(options.getConfigurationParameters()); + requestBuilder.configurationParametersResources(options.getConfigurationParametersResources()); return requestBuilder.build(); } diff --git a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfigurationParameters.java b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfigurationParameters.java index 5d6b95edd9ee..ed479a30b423 100644 --- a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfigurationParameters.java +++ b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherConfigurationParameters.java @@ -29,6 +29,7 @@ import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.util.ClassLoaderUtils; +import org.junit.platform.commons.util.CollectionUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ToStringBuilder; import org.junit.platform.engine.ConfigurationParameters; @@ -93,6 +94,7 @@ public String toString() { static final class Builder { private final Map explicitParameters = new HashMap<>(); + private final List configResources = new ArrayList<>(); private boolean implicitProvidersEnabled = true; private String configFileName = ConfigurationParameters.CONFIG_FILE_NAME; private ConfigurationParameters parentConfigurationParameters; @@ -106,6 +108,12 @@ Builder explicitParameters(Map parameters) { return this; } + Builder configurationResources(List configResources) { + Preconditions.notNull(configResources, "configResources must not be null"); + this.configResources.addAll(configResources); + return this; + } + Builder enableImplicitProviders(boolean enabled) { this.implicitProvidersEnabled = enabled; return this; @@ -129,6 +137,9 @@ LauncherConfigurationParameters build() { parameterProviders.add(ParameterProvider.explicit(explicitParameters)); } + CollectionUtils.forEachInReverseOrder(configResources, + configResource -> parameterProviders.add(ParameterProvider.propertiesFile(configResource))); + if (parentConfigurationParameters != null) { parameterProviders.add(ParameterProvider.inherited(parentConfigurationParameters)); } diff --git a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java index 1d2f22d7a559..7c6368e4c84b 100644 --- a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java +++ b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilder.java @@ -102,6 +102,7 @@ public final class LauncherDiscoveryRequestBuilder { private final List> discoveryFilters = new ArrayList<>(); private final List postDiscoveryFilters = new ArrayList<>(); private final Map configurationParameters = new HashMap<>(); + private final List configurationParametersResources = new ArrayList<>(); private final List discoveryListeners = new ArrayList<>(); private boolean implicitConfigurationParametersEnabled = true; private ConfigurationParameters parentConfigurationParameters; @@ -198,6 +199,30 @@ public LauncherDiscoveryRequestBuilder configurationParameters(Map propertiesFiles) { + Preconditions.notNull(propertiesFiles, "properties files must not be null"); + propertiesFiles.forEach(this::configurationParametersResource); + return this; + } + /** * Set the parent configuration parameters to use for the request. * @@ -296,6 +321,7 @@ public LauncherDiscoveryRequest build() { private LauncherConfigurationParameters buildLauncherConfigurationParameters() { Builder builder = LauncherConfigurationParameters.builder() // .explicitParameters(this.configurationParameters) // + .configurationResources(this.configurationParametersResources) // .enableImplicitProviders(this.implicitConfigurationParametersEnabled); if (parentConfigurationParameters != null) { diff --git a/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java b/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java index bbc87847f7c1..3dffe91c6049 100644 --- a/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java +++ b/junit-platform-runner/src/main/java/org/junit/platform/runner/JUnitPlatform.java @@ -30,6 +30,7 @@ import org.junit.platform.launcher.TestPlan; import org.junit.platform.launcher.core.LauncherFactory; import org.junit.platform.suite.api.ConfigurationParameter; +import org.junit.platform.suite.api.ConfigurationParametersResource; import org.junit.platform.suite.api.ExcludeClassNamePatterns; import org.junit.platform.suite.api.ExcludeEngines; import org.junit.platform.suite.api.ExcludePackages; @@ -105,6 +106,7 @@ * @see SuiteDisplayName * @see org.junit.platform.suite.api.UseTechnicalNames UseTechnicalNames * @see ConfigurationParameter + * @see ConfigurationParametersResource ConfigurationParametersResource * @deprecated since 1.8, in favor of the {@link Suite @Suite} support provided by * the {@code junit-platform-suite-engine} module; to be removed in JUnit Platform 2.0 */ diff --git a/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResource.java b/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResource.java new file mode 100644 index 000000000000..500f3ff0119f --- /dev/null +++ b/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResource.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.suite.api; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apiguardian.api.API; + +/** + * {@code @ConfigurationParametersResource} is an annotation that specifies + * a configuration file in property format to be added to the discovery request when running + * a test suite on the JUnit Platform. + * + * @since 1.11 + * @see DisableParentConfigurationParameters + * @see Suite + * @see org.junit.platform.runner.JUnitPlatform + * @see org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder#configurationParameter(String, String) + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +@Documented +// TODO: Before PR merge, change to STABLE/MAINTAINED +// TODO: Is version 1.11 correct? +@API(status = EXPERIMENTAL, since = "1.11") +@Repeatable(ConfigurationParametersResources.class) +public @interface ConfigurationParametersResource { + + /** + * The classpath location for the desired properties file; never {@code null} or blank. + */ + String resource(); + +} diff --git a/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResources.java b/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResources.java new file mode 100644 index 000000000000..834ed7edb20b --- /dev/null +++ b/junit-platform-suite-api/src/main/java/org/junit/platform/suite/api/ConfigurationParametersResources.java @@ -0,0 +1,50 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.suite.api; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apiguardian.api.API; + +/** + * {@code @ConfigurationParametersResources} is a container for one or more + * {@link ConfigurationParametersResource @ConfigurationParametersResource} declarations. + * + *

Note, however, that use of the {@code @ConfigurationParametersResources} container + * is completely optional since {@code @ConfigurationParametersResource} is a + * {@linkplain java.lang.annotation.Repeatable repeatable} annotation. + * + * @since 1.8 + * @see ConfigurationParametersResource + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +@Documented +// TODO: Before PR merge, change to STABLE/MAINTAINED +// TODO: Is version 1.11 correct? +@API(status = EXPERIMENTAL, since = "1.11") +public @interface ConfigurationParametersResources { + + /** + * An array of one or more {@link ConfigurationParametersResource @ConfigurationParameterResource} + * declarations. + */ + ConfigurationParametersResource[] value(); + +} diff --git a/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilder.java b/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilder.java index 08cb4aea20fa..675f6ee21aeb 100644 --- a/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilder.java +++ b/junit-platform-suite-commons/src/main/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilder.java @@ -45,6 +45,7 @@ import org.junit.platform.launcher.TagFilter; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; import org.junit.platform.suite.api.ConfigurationParameter; +import org.junit.platform.suite.api.ConfigurationParametersResource; import org.junit.platform.suite.api.DisableParentConfigurationParameters; import org.junit.platform.suite.api.ExcludeClassNamePatterns; import org.junit.platform.suite.api.ExcludeEngines; @@ -115,6 +116,11 @@ public SuiteLauncherDiscoveryRequestBuilder configurationParameters(Map suiteClass) { // @formatter:off findRepeatableAnnotations(suiteClass, ConfigurationParameter.class) .forEach(configuration -> configurationParameter(configuration.key(), configuration.value())); + findRepeatableAnnotations(suiteClass, ConfigurationParametersResource.class) + .forEach(configResource -> configurationParametersResource(configResource.resource())); findAnnotation(suiteClass, DisableParentConfigurationParameters.class) .ifPresent(__ -> enableParentConfigurationParameters = false); findAnnotationValues(suiteClass, ExcludeClassNamePatterns.class, ExcludeClassNamePatterns::value) diff --git a/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilderTests.java b/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilderTests.java index f75ee1017fd3..b2d6534682b0 100644 --- a/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilderTests.java +++ b/platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherDiscoveryRequestBuilderTests.java @@ -313,6 +313,48 @@ void multipleConfigurationParametersAddedByMap_areStoredInDiscoveryRequest() { assertThat(configParams.get("key1")).contains("value1"); assertThat(configParams.get("key2")).contains("value2"); } + + @Test + void configurationParametersResource_areStoredInDiscoveryRequest() { + // @formatter:off + var discoveryRequest = request() + .configurationParametersResource("config-test.properties") + .build(); + // @formatter:on + + var configParams = discoveryRequest.getConfigurationParameters(); + assertThat(configParams.get("com.example.prop.first")).contains("first value"); + assertThat(configParams.get("com.example.prop.second")).contains("second value"); + assertThat(configParams.get("com.example.prop.third")).contains("third value"); + } + + @Test + void configurationParametersResource_explicitConfigParametersOverrideResource() { + // @formatter:off + var discoveryRequest = request() + .configurationParametersResource("config-test.properties") + .configurationParameter("com.example.prop.first", "first value override") + .build(); + // @formatter:on + + var configParams = discoveryRequest.getConfigurationParameters(); + assertThat(configParams.get("com.example.prop.first")).contains("first value override"); + assertThat(configParams.get("com.example.prop.second")).contains("second value"); + } + + @Test + void configurationParametersResource_lastDeclaredResourceFileWins() { + // @formatter:off + var discoveryRequest = request() + .configurationParametersResource("config-test.properties") + .configurationParametersResource("config-test-override.properties") + .build(); + // @formatter:on + + var configParams = discoveryRequest.getConfigurationParameters(); + assertThat(configParams.get("com.example.prop.first")).contains("first value from override file"); + assertThat(configParams.get("com.example.prop.second")).contains("second value"); + } } @Nested diff --git a/platform-tests/src/test/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilderTests.java b/platform-tests/src/test/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilderTests.java index 1848163bc6ce..56d8108ded42 100644 --- a/platform-tests/src/test/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilderTests.java +++ b/platform-tests/src/test/java/org/junit/platform/suite/commons/SuiteLauncherDiscoveryRequestBuilderTests.java @@ -52,6 +52,8 @@ import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.PostDiscoveryFilter; import org.junit.platform.suite.api.ConfigurationParameter; +import org.junit.platform.suite.api.ConfigurationParametersResource; +import org.junit.platform.suite.api.ConfigurationParametersResources; import org.junit.platform.suite.api.DisableParentConfigurationParameters; import org.junit.platform.suite.api.ExcludeClassNamePatterns; import org.junit.platform.suite.api.ExcludeEngines; @@ -86,6 +88,48 @@ class Suite { assertEquals(Optional.of("*"), parameter); } + @Test + void configurationParametersResource() { + @ConfigurationParametersResource(resource = "config-test.properties") + class Suite { + } + + LauncherDiscoveryRequest request = builder.suite(Suite.class).build(); + ConfigurationParameters configuration = request.getConfigurationParameters(); + Optional parameter = configuration.get("com.example.prop.first"); + assertEquals(Optional.of("first value"), parameter); + } + + @Test + void configurationParametersResources() { + @ConfigurationParametersResources({ @ConfigurationParametersResource(resource = "config-test.properties"), + @ConfigurationParametersResource(resource = "config-test-override.properties") }) + class Suite { + } + + LauncherDiscoveryRequest request = builder.suite(Suite.class).build(); + ConfigurationParameters configuration = request.getConfigurationParameters(); + Optional parameterOne = configuration.get("com.example.prop.first"); + assertEquals(Optional.of("first value from override file"), parameterOne); + Optional parameterTwo = configuration.get("com.example.prop.second"); + assertEquals(Optional.of("second value"), parameterTwo); + } + + @Test + void configurationParametersResource_explicitParametersTakePrecedence() { + @ConfigurationParametersResource(resource = "config-test.properties") + @ConfigurationParameter(key = "com.example.prop.first", value = "first value from explicit parameter") + class Suite { + } + + LauncherDiscoveryRequest request = builder.suite(Suite.class).build(); + ConfigurationParameters configuration = request.getConfigurationParameters(); + Optional parameterOne = configuration.get("com.example.prop.first"); + assertEquals(Optional.of("first value from explicit parameter"), parameterOne); + Optional parameterTwo = configuration.get("com.example.prop.second"); + assertEquals(Optional.of("second value"), parameterTwo); + } + @Test void excludeClassNamePatterns() { class TestCase { diff --git a/platform-tests/src/test/resources/config-test-override.properties b/platform-tests/src/test/resources/config-test-override.properties new file mode 100644 index 000000000000..302230b0d3b5 --- /dev/null +++ b/platform-tests/src/test/resources/config-test-override.properties @@ -0,0 +1,2 @@ +# Used in tests, don't delete me +com.example.prop.first=first value from override file diff --git a/platform-tests/src/test/resources/config-test.properties b/platform-tests/src/test/resources/config-test.properties new file mode 100644 index 000000000000..10f838f11b0e --- /dev/null +++ b/platform-tests/src/test/resources/config-test.properties @@ -0,0 +1,4 @@ +# Used in tests, don't delete me +com.example.prop.first=first value +com.example.prop.second=second value +com.example.prop.third=third value