diff --git a/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc index 81a5dff837d3..b1d89d84b938 100644 --- a/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc +++ b/documentation/modules/ROOT/pages/writing-tests/parallel-execution.adoc @@ -164,22 +164,18 @@ concurrently. You can configure which implementation of `HierarchicalTestExecuto is used be setting the `junit.jupiter.execution.parallel.config.executor-service` configuration parameter to one of the following options: -`fork_join_pool` (default):: +`worker_thread_pool` (default):: +Use an executor service that is backed by a `ThreadPoolExecutor`. The +executor service tries to maintain the desired parallelism but does +not compensate for test or production code using blocking APIs in the JDK. + +`fork_join_pool`:: Use an executor service that is backed by a `ForkJoinPool` from the JDK. This will cause tests to be executed in a `ForkJoinWorkerThread`. In some cases, usages of `ForkJoinPool` in test or production code or calls to blocking JDK APIs may cause the number of concurrently executing tests to increase. To avoid this situation, please use `worker_thread_pool`. -`worker_thread_pool` (experimental):: -Use an executor service that is backed by a regular thread pool and does not create -additional threads if test or production code uses `ForkJoinPool` or calls a blocking -API in the JDK. - -WARNING: Using `worker_thread_pool` is currently an _experimental_ feature. You're invited -to give it a try and provide feedback to the JUnit team so they can improve and eventually -xref:api-evolution.adoc[promote] this feature. - [[config-strategies]] === Strategies @@ -241,7 +237,7 @@ xref:running-tests/configuration-parameters.adoc[] for details on how to set suc `junit.jupiter.execution.parallel.config.executor-service=fork_join_pool|worker_thread_pool`:: Type of `HierarchicalTestExecutorService` to use for parallel execution (defaults to - `fork_join_pool`). + `worker_thread_pool`). `junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`:: Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`). diff --git a/documentation/modules/ROOT/partials/release-notes/release-notes-6.2.0-M1.adoc b/documentation/modules/ROOT/partials/release-notes/release-notes-6.2.0-M1.adoc index 0fb2d33ae821..1f16eb47ea61 100644 --- a/documentation/modules/ROOT/partials/release-notes/release-notes-6.2.0-M1.adoc +++ b/documentation/modules/ROOT/partials/release-notes/release-notes-6.2.0-M1.adoc @@ -46,6 +46,8 @@ repository on GitHub. xref:advanced-topics/configuration-parameter-documentation.adoc[Documenting Configuration Parameters] for more information. * Platform configuration parameters are documented in `META-INF/junit-platform-configuration-metadata.json` +* Test engines using the `ParallelHierarchicalTestExecutorServiceFactory` now use the + `WORKER_THREAD_POOL` executor service by default. [[v6.2.0-M1-junit-jupiter]] === JUnit Jupiter @@ -81,6 +83,8 @@ repository on GitHub. * The `assertTimeout`, `assertTimeoutPreemptively` and methods annotated with `@Timeout` now measure the execution time with sub-millisecond precision. * Jupiter configuration parameters are documented in `META-INF/junit-platform-configuration-metadata.json` +* The `junit.jupiter.execution.parallel.config.executor-service` configuration parameter + now defaults to `WORKER_THREAD_POOL` when parallel execution is enabled. [[v6.2.0-M1-junit-vintage]] === JUnit Vintage diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java index 9a0841fb913b..2c1131953860 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/DefaultJupiterConfiguration.java @@ -29,14 +29,11 @@ import static org.junit.jupiter.api.Constants.EXTENSIONS_AUTODETECTION_INCLUDE_PROPERTY_NAME; import static org.junit.jupiter.api.Constants.EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME; import static org.junit.jupiter.api.Constants.INCLUDE_ALL_EXTENSIONS_PATTERN; -import static org.junit.jupiter.api.Constants.PARALLEL_CONFIG_EXECUTOR_SERVICE_PROPERTY_NAME; import static org.junit.jupiter.api.Constants.PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME; import static org.junit.jupiter.api.Defaults.CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_DEFAULT; import static org.junit.jupiter.api.Defaults.EXTENSIONS_AUTODETECTION_ENABLED_DEFAULT; import static org.junit.jupiter.api.Defaults.PARALLEL_EXECUTION_ENABLED_DEFAULT; import static org.junit.jupiter.engine.config.FilteringConfigurationParameterConverter.exclude; -import static org.junit.platform.engine.support.hierarchical.ParallelHierarchicalTestExecutorServiceFactory.ParallelExecutorServiceType.FORK_JOIN_POOL; -import static org.junit.platform.engine.support.hierarchical.ParallelHierarchicalTestExecutorServiceFactory.ParallelExecutorServiceType.WORKER_THREAD_POOL; import java.util.List; import java.util.Optional; @@ -129,17 +126,6 @@ private void validateConfigurationParameters(DiscoveryIssueReporter issueReporte Please remove it from your configuration.""".formatted(key)); issueReporter.reportIssue(warning); })); - if (isParallelExecutionEnabled() - && configurationParameters.get(PARALLEL_CONFIG_EXECUTOR_SERVICE_PROPERTY_NAME).isEmpty()) { - var info = DiscoveryIssue.create(Severity.INFO, - "Parallel test execution is enabled but the default ForkJoinPool-based executor service will be used. " - + "Please give the new implementation based on a regular thread pool a try by setting the '" - + PARALLEL_CONFIG_EXECUTOR_SERVICE_PROPERTY_NAME + "' configuration parameter to '" - + WORKER_THREAD_POOL + "' and report any issues to the JUnit team. " - + "Alternatively, set the configuration parameter to '" + FORK_JOIN_POOL - + "' to hide this message and keep using the original implementation."); - issueReporter.reportIssue(info); - } } @Override diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelHierarchicalTestExecutorServiceFactory.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelHierarchicalTestExecutorServiceFactory.java index d5102597a021..2b74e533ba79 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelHierarchicalTestExecutorServiceFactory.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/ParallelHierarchicalTestExecutorServiceFactory.java @@ -10,7 +10,6 @@ package org.junit.platform.engine.support.hierarchical; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.MAINTAINED; import java.util.Locale; @@ -36,7 +35,7 @@ public final class ParallelHierarchicalTestExecutorServiceFactory { * Default value for {@value #EXECUTOR_SERVICE_PROPERTY_NAME} is {@value}. */ @API(status = MAINTAINED, since = "6.2") - public static final String EXECUTOR_SERVICE_DEFAULT = "FORK_JOIN_POOL"; + public static final String EXECUTOR_SERVICE_DEFAULT = "WORKER_THREAD_POOL"; /** * Property name used to determine the desired @@ -117,7 +116,7 @@ public enum ParallelExecutorServiceType { * Indicates that {@link WorkerThreadPoolHierarchicalTestExecutorService} * should be used. */ - @API(status = EXPERIMENTAL, since = "6.1") + @API(status = MAINTAINED, since = "6.2") WORKER_THREAD_POOL; private static ParallelExecutorServiceType parse(String value) { diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/WorkerThreadPoolHierarchicalTestExecutorService.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/WorkerThreadPoolHierarchicalTestExecutorService.java index 7af0e08609bb..79bd40c8ca71 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/WorkerThreadPoolHierarchicalTestExecutorService.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/WorkerThreadPoolHierarchicalTestExecutorService.java @@ -15,7 +15,7 @@ import static java.util.Objects.requireNonNull; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.apiguardian.api.API.Status.MAINTAINED; import static org.junit.platform.commons.util.ExceptionUtils.throwAsUncheckedException; import static org.junit.platform.engine.support.hierarchical.ExclusiveResource.GLOBAL_READ_WRITE; import static org.junit.platform.engine.support.hierarchical.Node.ExecutionMode.SAME_THREAD; @@ -67,7 +67,7 @@ * @see ParallelExecutorServiceType#WORKER_THREAD_POOL * @see DefaultParallelExecutionConfigurationStrategy */ -@API(status = EXPERIMENTAL, since = "6.1") +@API(status = MAINTAINED, since = "6.2") public final class WorkerThreadPoolHierarchicalTestExecutorService implements HierarchicalTestExecutorService { /* diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java index 055558760630..8bc652a9eff4 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java @@ -46,7 +46,6 @@ import org.junit.jupiter.params.provider.EnumSource; import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.DiscoveryIssue; -import org.junit.platform.engine.DiscoveryIssue.Severity; import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter; import org.junit.platform.engine.support.hierarchical.ParallelHierarchicalTestExecutorServiceFactory.ParallelExecutorServiceType; import org.junit.platform.launcher.core.ConfigurationParametersFactoryForTests; @@ -187,22 +186,6 @@ void doesNotReportAnyIssuesIfParallelExecutionIsEnabledAndConfigurationParameter assertThat(issues).isEmpty(); } - @Test - void asksUsersToTryWorkerThreadPoolHierarchicalExecutorServiceIfParallelExecutionIsEnabled() { - var parameters = Map.of(Constants.PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME, true); - List issues = new ArrayList<>(); - - new DefaultJupiterConfiguration(configurationParameters(parameters), dummyOutputDirectoryCreator(), - DiscoveryIssueReporter.collecting(issues)).getDefaultTestInstanceLifecycle(); - - assertThat(issues).containsExactly(DiscoveryIssue.create(Severity.INFO, """ - Parallel test execution is enabled but the default ForkJoinPool-based executor service will be used. \ - Please give the new implementation based on a regular thread pool a try by setting the \ - 'junit.jupiter.execution.parallel.config.executor-service' configuration parameter to \ - 'WORKER_THREAD_POOL' and report any issues to the JUnit team. Alternatively, set the configuration \ - parameter to 'FORK_JOIN_POOL' to hide this message and keep using the original implementation.""")); - } - private void assertDefaultConfigParam(@Nullable String configValue, Lifecycle expected) { var lifecycle = getDefaultTestInstanceLifecycleConfigParam(configValue); assertThat(lifecycle).isEqualTo(expected);