Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
892492a
Add support for executing a single task
marcphilipp Oct 9, 2025
5c9f0f6
Verify that `invokeAll()` is only called internally
marcphilipp Oct 9, 2025
a71f232
Add support for executing children concurrently
marcphilipp Oct 9, 2025
1c703f0
Add support for executing children in same thread
marcphilipp Oct 9, 2025
c0a9d42
Always execute single child in same thread as its parent
marcphilipp Oct 9, 2025
df84bf6
Polishing
marcphilipp Oct 9, 2025
bd426ec
Use fixed thread pool
marcphilipp Oct 9, 2025
0947a89
Implement basic work stealing
marcphilipp Oct 9, 2025
58ac3d1
Polishing
marcphilipp Oct 9, 2025
a11039c
Configure timeout for all tests
marcphilipp Oct 9, 2025
58198ae
Introduce `ResourceLock.tryAcquire`
marcphilipp Oct 9, 2025
bb835e1
Acquire resource locks for tasks
marcphilipp Oct 9, 2025
67db7ba
Polish tests
marcphilipp Oct 9, 2025
4a231aa
Fix race condition
marcphilipp Oct 9, 2025
2dc1f3f
Change thread pool configuration to achieve more parallelism
marcphilipp Oct 9, 2025
b869706
Polishing
marcphilipp Oct 10, 2025
f70433b
Introduce worker leases to limit parallelism
marcphilipp Oct 10, 2025
ef2c49d
Add constructor needed by Jupiter
marcphilipp Oct 10, 2025
ff783e9
Add support for blocking inside of worker thread
marcphilipp Oct 10, 2025
752d565
Add support for submitting SAME_THREAD child tasks dynamically
marcphilipp Oct 12, 2025
0223336
Run isolated tasks last to maximize parallelism
marcphilipp Oct 12, 2025
332abe1
Polish logging
marcphilipp Oct 12, 2025
2df6b28
Stop workers sooner (without waiting for queue entries or worker lease)
marcphilipp Oct 12, 2025
c3032be
Use new implementation
marcphilipp Oct 12, 2025
5f3fd13
Improve logging pattern
marcphilipp Oct 12, 2025
d33beb5
Delete debug printing code
marcphilipp Oct 13, 2025
2264989
Prioritize children of started containers
marcphilipp Oct 13, 2025
8c9db08
Improve naming
marcphilipp Oct 13, 2025
539ef1a
Improve logging
marcphilipp Oct 13, 2025
86dfea4
Poll queue only if worker lease was available
marcphilipp Oct 13, 2025
05c45f9
Simplify tests
marcphilipp Oct 13, 2025
9d77839
Introduce configuration parameter for opting in to new implementation
marcphilipp Oct 13, 2025
0d201d1
Remove double negative
marcphilipp Oct 14, 2025
08568e4
Let `WorkerLease` implement `AutoCloseable` to simplify handling
marcphilipp Oct 14, 2025
a05279a
Use same (reverse) order for work stealing and work queue
marcphilipp Oct 14, 2025
1055dbb
Prioritize tests over containers
marcphilipp Oct 14, 2025
a545da0
Move `invokeAll()`` code to `WorkerThread`
marcphilipp Oct 14, 2025
1196b17
Hold back one task for the current worker when forking
marcphilipp Oct 14, 2025
e0bc61b
Implement work stealing for dynamic children
marcphilipp Oct 14, 2025
261ac0e
Limit work stealing of dynamic children to current entry
marcphilipp Oct 14, 2025
cf923fc
Polishing
marcphilipp Oct 14, 2025
afbb9f6
Simplify work-stealing `Future` implementation
marcphilipp Oct 14, 2025
a8cec38
Restore max pool size limit in test
marcphilipp Oct 14, 2025
6103e4d
Avoid starting an excessive number of threads
marcphilipp Oct 14, 2025
855880f
Polishing
marcphilipp Oct 14, 2025
d47f9fc
Add test for `WorkerLeaseManager` and `WorkerLease`
marcphilipp Oct 16, 2025
ba98383
Avoid race during worker startup
marcphilipp Oct 16, 2025
d111712
Add test for race condition when starting workers
mpkorstanje Oct 17, 2025
55d8b71
Avoid recursively calling `maybeStartWorker`
marcphilipp Oct 17, 2025
c8ddb46
Repeat test to increase likelihood of triggering its flakiness
marcphilipp Oct 17, 2025
4de2d9a
Temporarily disable stacktrace pruning
marcphilipp Oct 17, 2025
f081fde
Temporarily enable logging to have more info when tests fail
marcphilipp Oct 17, 2025
ed9b22d
Execute unclaimed children in blocking mode prior to joining forked work
marcphilipp Oct 17, 2025
163b72c
Ignore rejected worker starts if there's at least one active worker
marcphilipp Oct 17, 2025
be1ab01
Reinstate max-pool-size limit
marcphilipp Oct 17, 2025
7c74974
Use unique ID as key
marcphilipp Oct 18, 2025
03a1dd8
Simplify forking and work stealing
marcphilipp Oct 18, 2025
82a2d7f
Yield worker lease when blocking thread can continue
marcphilipp Oct 18, 2025
8cf7f47
Add TODO
marcphilipp Oct 18, 2025
2cc5311
fixup! Yield worker lease when blocking thread can continue
marcphilipp Oct 18, 2025
08986fb
Use EnumMap for queueEntriesByResult
mpkorstanje Oct 19, 2025
4567c16
Verify work is stolen in reverse order
mpkorstanje Oct 19, 2025
6e64a19
Ensure work is stolen in reverse order
mpkorstanje Oct 19, 2025
0d5e8e1
Fix prioritizesChildrenOfStartedContainers by swapping order
mpkorstanje Oct 19, 2025
f045138
Ensure task entry index is not sparse
mpkorstanje Oct 19, 2025
fdb5fac
Typos and formatting
mpkorstanje Oct 19, 2025
14d5f9a
Polishing
marcphilipp Oct 24, 2025
53af729
Fix flakey test?
mpkorstanje Oct 19, 2025
569edce
Test is not flaky anymore.
mpkorstanje Oct 20, 2025
a9ae858
Improve naming
mpkorstanje Oct 19, 2025
bc9d6b2
Skip over unavailable resources
mpkorstanje Oct 19, 2025
807ea54
Remove unused entry ordering
mpkorstanje Oct 20, 2025
192b0b4
Polishing
mpkorstanje Oct 20, 2025
2c72021
Polishing with spotless
mpkorstanje Oct 20, 2025
87416c1
Polishing
mpkorstanje Oct 20, 2025
d691b1e
Extract RejectedExecutionHandler to avoid control flow by exception
mpkorstanje Oct 20, 2025
b5df82e
Use ConcurrentSkipListSet with absolute ordering to back work queue
mpkorstanje Oct 21, 2025
a4d7ed6
Use long index, because containers are int size
mpkorstanje Oct 21, 2025
b11a481
Polishing
marcphilipp Oct 24, 2025
8ef8d20
Steal other dynamic children before blocking
marcphilipp Oct 25, 2025
80c38d8
Only steal queue entries for siblings of dynamic children
marcphilipp Oct 26, 2025
b3b1345
Polishing
marcphilipp Oct 26, 2025
3ed8f0f
Revert "Introduce configuration parameter for opting in to new implem…
marcphilipp Oct 28, 2025
fc59fc2
Rename new implementation
marcphilipp Oct 28, 2025
d178918
Introduce `ConcurrentHierarchicalTestExecutorServiceFactory`
marcphilipp Oct 28, 2025
de88e08
Disable logging
marcphilipp Oct 29, 2025
9bfc272
Use regular `@Test` methods
marcphilipp Oct 29, 2025
87c8bd9
Document new public types
marcphilipp Oct 29, 2025
78b58ec
Polishing
marcphilipp Oct 29, 2025
2cf5caf
Deprecate `ForkJoinPoolHierarchicalTestExecutorService` constructors
marcphilipp Oct 29, 2025
94ad193
Report info-level discovery message when `ForkJoinPool` is used
marcphilipp Oct 29, 2025
b3d17ad
Document how to use `worker_thread_pool` executor service
marcphilipp Oct 29, 2025
1e645e4
Add to release notes
marcphilipp Oct 29, 2025
7a250e0
Apply feedback
marcphilipp Oct 29, 2025
d34465f
Merge branch 'main' into marc/parallel-execution-custom-implementation
marcphilipp Oct 29, 2025
a392f00
Use `@NonNull` from JSpecify
marcphilipp Oct 29, 2025
979a1be
Run more tests against both implementations
marcphilipp Oct 30, 2025
663b690
Rename to `Parallel...` instead of `Concurrent...` for consistency
marcphilipp Oct 30, 2025
1f9ffde
Compare queue entries by unique id
mpkorstanje Nov 3, 2025
592a05e
Retain invoke all order
mpkorstanje Nov 3, 2025
86af266
Polishing
mpkorstanje Nov 3, 2025
8d1ec79
Track dynamic children by index
mpkorstanje Nov 3, 2025
342e97f
Fix test
marcphilipp Nov 4, 2025
859ce99
Merge remote-tracking branch 'origin/main' into marc/parallel-executi…
marcphilipp Nov 4, 2025
4819a72
Convert `Entry` to regular class
marcphilipp Nov 4, 2025
33c1a39
Always use `nextChildIndex()`
marcphilipp Nov 4, 2025
20eb693
Use `Comparator`
marcphilipp Nov 4, 2025
ee46f96
Use insertion order
marcphilipp Nov 4, 2025
fdd596b
Use thenComparing with key extractor and comparator
mpkorstanje Nov 4, 2025
965c42a
Use Arrays.asList to create an ArrayList
mpkorstanje Nov 4, 2025
1ea7dc7
Name leaves after their parents
mpkorstanje Nov 4, 2025
02623f2
Order elements
mpkorstanje Nov 4, 2025
a52149e
Wait for children in order
marcphilipp Nov 5, 2025
d013d31
Repeat flaky test (to be fixed)
marcphilipp Nov 5, 2025
10f1dbf
Make worker start at head of queue again after executing a node
marcphilipp Nov 5, 2025
b647f0b
Reduce complexity by duplication
mpkorstanje Nov 5, 2025
bd24b6f
Simplify
marcphilipp Nov 6, 2025
ea28eee
Improve discovery issue message
marcphilipp Nov 6, 2025
98d7ce8
Polish release note entry
marcphilipp Nov 6, 2025
8495e8b
Improve internal documentation
marcphilipp Nov 6, 2025
e1f0d9d
Polish test
mpkorstanje Nov 6, 2025
e7791ae
Skip over locked entries that were stolen
mpkorstanje Nov 6, 2025
bd6ba90
Merge remote-tracking branch 'origin/main' into marc/parallel-executi…
mpkorstanje Nov 6, 2025
4500b7e
Merge branch 'main' into marc/parallel-execution-custom-implementation
marcphilipp Nov 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,20 @@ repository on GitHub.
[[release-notes-6.1.0-M1-junit-platform-deprecations-and-breaking-changes]]
==== Deprecations and Breaking Changes

* ❓
* Deprecate constructors for `ForkJoinPoolHierarchicalTestExecutorService` in favor of the
new `ParallelHierarchicalTestExecutorServiceFactory` that also supports
`WorkerThreadPoolHierarchicalTestExecutorService`.

[[release-notes-6.1.0-M1-junit-platform-new-features-and-improvements]]
==== New Features and Improvements

* Support for creating a `ModuleSelector` from a `java.lang.Module` and using
its classloader for test discovery.
* New `WorkerThreadPoolHierarchicalTestExecutorService` implementation used for parallel
test execution that is backed by a regular thread pool rather than a `ForkJoinPool`.
Engine authors should switch to use `ParallelHierarchicalTestExecutorServiceFactory`
rather than instantiating a concrete `HierarchicalTestExecutorService` implementation
for parallel execution directly.
* `OpenTestReportGeneratingListener` now supports redirecting XML events to a socket via
the new `junit.platform.reporting.open.xml.socket` configuration parameter. When set to a
port number, events are sent to `127.0.0.1:<port>` instead of being written to a file.
Expand Down Expand Up @@ -61,6 +68,13 @@ repository on GitHub.
* Enrich `assertInstanceOf` failure using the test subject `Throwable` as cause. It
results in the stack trace of the test subject `Throwable` to get reported along with
the failure.
* Make implementation of `HierarchicalTestExecutorService` used for parallel test
execution configurable via the new
`junit.jupiter.execution.parallel.config.executor-service` configuration parameter to
in order to add support for `WorkerThreadPoolHierarchicalTestExecutorService`. Please
refer to the
<<../user-guide/index.adoc#writing-tests-parallel-execution-config-executor-service, User Guide>>
for details.

[[release-notes-6.1.0-M1-junit-vintage]]
=== JUnit Vintage
Expand Down
178 changes: 92 additions & 86 deletions documentation/src/docs/asciidoc/user-guide/writing-tests.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3433,6 +3433,33 @@ used instead.
[[writing-tests-parallel-execution-config]]
==== Configuration

[[writing-tests-parallel-execution-config-executor-service]]
===== Executor Service

If parallel execution is enabled, a thread pool is used behind the scenes to execute tests
concurrently. You can configure which implementation of `HierarchicalTestExecutorService`
is used be setting the `junit.jupiter.execution.parallel.config.executor-service`
configuration parameter to one of the following options:

`fork_join_pool` (default)::
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
<<api-evolution, promote>> this feature.

[[writing-tests-parallel-execution-config-strategies]]
===== Strategies

Properties such as the desired parallelism and the maximum pool size can be configured
using a `{ParallelExecutionConfigurationStrategy}`. The JUnit Platform provides two
implementations out of the box: `dynamic` and `fixed`. Alternatively, you may implement a
Expand Down Expand Up @@ -3464,13 +3491,12 @@ strategy with a factor of `1`. Consequently, the desired parallelism will be equ
number of available processors/cores.

.Parallelism alone does not imply maximum number of concurrent threads
NOTE: By default JUnit Jupiter does not guarantee that the number of concurrently
executing tests will not exceed the configured parallelism. For example, when using one
of the synchronization mechanisms described in the next section, the `ForkJoinPool` that
is used behind the scenes may spawn additional threads to ensure execution continues with
sufficient parallelism.
If you require such guarantees, it is possible to limit the maximum number of concurrent
threads by controlling the maximum pool size of the `dynamic`, `fixed` and `custom`
NOTE: By default, JUnit Jupiter does not guarantee that the number of threads used to
execute test will not exceed the configured parallelism. For example, when using one
of the synchronization mechanisms described in the next section, the executor service
implementation may spawn additional threads to ensure execution continues with sufficient
parallelism. If you require such guarantees, it is possible to limit the maximum number of
threads by configuring the maximum pool size of the `dynamic`, `fixed` and `custom`
strategies.

[[writing-tests-parallel-execution-config-properties]]
Expand All @@ -3479,86 +3505,66 @@ strategies.
The following table lists relevant properties for configuring parallel execution. See
<<running-tests-config-params>> for details on how to set such properties.

[cols="d,d,a,d"]
|===
|Property |Description |Supported Values |Default Value

| ```junit.jupiter.execution.parallel.enabled```
| Enable parallel test execution
|
* `true`
* `false`
| ```false```

| ```junit.jupiter.execution.parallel.mode.default```
| Default execution mode of nodes in the test tree
|
* `concurrent`
* `same_thread`
| ```same_thread```

| ```junit.jupiter.execution.parallel.mode.classes.default```
| Default execution mode of top-level classes
|
* `concurrent`
* `same_thread`
| ```same_thread```

| ```junit.jupiter.execution.parallel.config.strategy```
| Execution strategy for desired parallelism and maximum pool size
|
* `dynamic`
* `fixed`
* `custom`
| ```dynamic```

| ```junit.jupiter.execution.parallel.config.dynamic.factor```
| Factor to be multiplied by the number of available processors/cores to determine the
desired parallelism for the ```dynamic``` configuration strategy
| a positive decimal number
| ```1.0```

| ```junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor```
| Factor to be multiplied by the number of available processors/cores and the value of
====== General

`junit.jupiter.execution.parallel.enabled=true|false`::
Enable/disable parallel test execution (defaults to `false`).

`junit.jupiter.execution.parallel.mode.default=concurrent|same_thread`::
Default execution mode of nodes in the test tree (defaults to `same_thread`).

`junit.jupiter.execution.parallel.mode.classes.default=concurrent|same_thread`::
Default execution mode of top-level classes (defaults to `same_thread`).

`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`).

`junit.jupiter.execution.parallel.config.strategy=dynamic|fixed|custom`::
Execution strategy for desired parallelism, maximum pool size, etc. (defaults to `dynamic`).

====== Dynamic strategy

`junit.jupiter.execution.parallel.config.dynamic.factor=decimal`::
Factor to be multiplied by the number of available processors/cores to determine the
desired parallelism for the ```dynamic``` configuration strategy.
Must be a positive decimal number (defaults to `1.0`).

`junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=decimal`::
Factor to be multiplied by the number of available processors/cores and the value of
`junit.jupiter.execution.parallel.config.dynamic.factor` to determine the desired
parallelism for the ```dynamic``` configuration strategy
| a positive decimal number, must be greater than or equal to `1.0`
| 256 + the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied
by the number of available processors/cores

| ```junit.jupiter.execution.parallel.config.dynamic.saturate```
| Disable saturation of the underlying fork-join pool for the ```dynamic``` configuration
strategy
|
* `true`
* `false`
| ```true```

| ```junit.jupiter.execution.parallel.config.fixed.parallelism```
| Desired parallelism for the ```fixed``` configuration strategy
| a positive integer
| no default value

| ```junit.jupiter.execution.parallel.config.fixed.max-pool-size```
| Desired maximum pool size of the underlying fork-join pool for the ```fixed```
configuration strategy
| a positive integer, must be greater than or equal to `junit.jupiter.execution.parallel.config.fixed.parallelism`
| 256 + the value of `junit.jupiter.execution.parallel.config.fixed.parallelism`

| ```junit.jupiter.execution.parallel.config.fixed.saturate```
| Disable saturation of the underlying fork-join pool for the ```fixed``` configuration
strategy
|
* `true`
* `false`
| ```true```

| ```junit.jupiter.execution.parallel.config.custom.class```
| Fully qualified class name of the _ParallelExecutionConfigurationStrategy_ to be
used for the ```custom``` configuration strategy
| for example, _org.example.CustomStrategy_
| no default value
|===
parallelism for the ```dynamic``` configuration strategy.
Must be a positive decimal number greater than or equal to `1.0` (defaults to 256 plus
the value of `junit.jupiter.execution.parallel.config.dynamic.factor` multiplied by the
number of available processors/cores)

`junit.jupiter.execution.parallel.config.dynamic.saturate=true|false`::
Enable/disable saturation of the underlying `ForkJoinPool` for the ```dynamic```
configuration strategy (defaults to `true`). Only used if
`junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`.

====== Fixed strategy

`junit.jupiter.execution.parallel.config.fixed.parallelism=integer`::
Desired parallelism for the ```fixed``` configuration strategy (no default value). Must
be a positive integer.

`junit.jupiter.execution.parallel.config.fixed.max-pool-size=integer`::
Desired maximum pool size of the underlying fork-join pool for the ```fixed```
configuration strategy. Must be a positive integer greater than or equal to
`junit.jupiter.execution.parallel.config.fixed.parallelism` (defaults to 256 plus the
value of `junit.jupiter.execution.parallel.config.fixed.parallelism`).

`junit.jupiter.execution.parallel.config.fixed.saturate=true|false`::
Enable/disable saturation of the underlying `ForkJoinPool` for the ```fixed```
configuration strategy (defaults to `true`). Only used if
`junit.jupiter.execution.parallel.config.executor-service` is set to `fork_join_pool`.

====== Custom strategy

`junit.jupiter.execution.parallel.config.custom.class=classname`::
Fully qualified class name of the `ParallelExecutionConfigurationStrategy` to be used
for the ```custom``` configuration strategy (no default value).

[[writing-tests-parallel-execution-synchronization]]
==== Synchronization
Expand Down
1 change: 1 addition & 0 deletions documentation/src/test/resources/junit-platform.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.executor-service=worker_thread_pool
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.config.fixed.parallelism=6

Expand Down
2 changes: 1 addition & 1 deletion documentation/src/test/resources/log4j2-test.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-config-2.xsd">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<PatternLayout pattern="%d{HH:mm:ss.SSSSSS} [%-18t] %-5level %logger{1.} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import org.junit.jupiter.engine.config.JupiterConfiguration;
import org.junit.platform.commons.util.ClassNamePatternFilterUtils;
import org.junit.platform.engine.support.hierarchical.ParallelExecutionConfigurationStrategy;
import org.junit.platform.engine.support.hierarchical.ParallelHierarchicalTestExecutorServiceFactory;
import org.junit.platform.engine.support.hierarchical.ParallelHierarchicalTestExecutorServiceFactory.ParallelExecutorServiceType;

/**
* Collection of constants related to the {@link JupiterTestEngine}.
Expand Down Expand Up @@ -237,7 +239,21 @@ public final class Constants {
@API(status = STABLE, since = "5.10")
public static final String DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME = Execution.DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME;

static final String PARALLEL_CONFIG_PREFIX = "junit.jupiter.execution.parallel.config.";
/**
* Property name used to determine the desired
* {@link ParallelExecutorServiceType ParallelExecutorServiceType}:
* {@value}
*
* <p>Value must be
* {@link ParallelExecutorServiceType#FORK_JOIN_POOL FORK_JOIN_POOL} or
* {@link ParallelExecutorServiceType#WORKER_THREAD_POOL WORKER_THREAD_POOL},
* ignoring case.
*
* @since 6.1
* @see ParallelHierarchicalTestExecutorServiceFactory
*/
@API(status = EXPERIMENTAL, since = "6.1")
public static final String PARALLEL_CONFIG_EXECUTOR_SERVICE_PROPERTY_NAME = JupiterConfiguration.PARALLEL_CONFIG_EXECUTOR_SERVICE_PROPERTY_NAME;

/**
* Property name used to select the
Expand All @@ -249,7 +265,7 @@ public final class Constants {
* @since 5.3
*/
@API(status = STABLE, since = "5.10")
public static final String PARALLEL_CONFIG_STRATEGY_PROPERTY_NAME = PARALLEL_CONFIG_PREFIX
public static final String PARALLEL_CONFIG_STRATEGY_PROPERTY_NAME = JupiterConfiguration.PARALLEL_CONFIG_PREFIX
+ CONFIG_STRATEGY_PROPERTY_NAME;

/**
Expand All @@ -261,7 +277,7 @@ public final class Constants {
* @since 5.3
*/
@API(status = STABLE, since = "5.10")
public static final String PARALLEL_CONFIG_FIXED_PARALLELISM_PROPERTY_NAME = PARALLEL_CONFIG_PREFIX
public static final String PARALLEL_CONFIG_FIXED_PARALLELISM_PROPERTY_NAME = JupiterConfiguration.PARALLEL_CONFIG_PREFIX
+ CONFIG_FIXED_PARALLELISM_PROPERTY_NAME;

/**
Expand All @@ -275,7 +291,7 @@ public final class Constants {
* @since 5.10
*/
@API(status = MAINTAINED, since = "5.13.3")
public static final String PARALLEL_CONFIG_FIXED_MAX_POOL_SIZE_PROPERTY_NAME = PARALLEL_CONFIG_PREFIX
public static final String PARALLEL_CONFIG_FIXED_MAX_POOL_SIZE_PROPERTY_NAME = JupiterConfiguration.PARALLEL_CONFIG_PREFIX
+ CONFIG_FIXED_MAX_POOL_SIZE_PROPERTY_NAME;

/**
Expand All @@ -291,7 +307,7 @@ public final class Constants {
* @since 5.10
*/
@API(status = MAINTAINED, since = "5.13.3")
public static final String PARALLEL_CONFIG_FIXED_SATURATE_PROPERTY_NAME = PARALLEL_CONFIG_PREFIX
public static final String PARALLEL_CONFIG_FIXED_SATURATE_PROPERTY_NAME = JupiterConfiguration.PARALLEL_CONFIG_PREFIX
+ CONFIG_FIXED_SATURATE_PROPERTY_NAME;

/**
Expand All @@ -304,7 +320,7 @@ public final class Constants {
* @since 5.3
*/
@API(status = STABLE, since = "5.10")
public static final String PARALLEL_CONFIG_DYNAMIC_FACTOR_PROPERTY_NAME = PARALLEL_CONFIG_PREFIX
public static final String PARALLEL_CONFIG_DYNAMIC_FACTOR_PROPERTY_NAME = JupiterConfiguration.PARALLEL_CONFIG_PREFIX
+ CONFIG_DYNAMIC_FACTOR_PROPERTY_NAME;

/**
Expand All @@ -315,7 +331,7 @@ public final class Constants {
* @since 5.3
*/
@API(status = STABLE, since = "5.10")
public static final String PARALLEL_CONFIG_CUSTOM_CLASS_PROPERTY_NAME = PARALLEL_CONFIG_PREFIX
public static final String PARALLEL_CONFIG_CUSTOM_CLASS_PROPERTY_NAME = JupiterConfiguration.PARALLEL_CONFIG_PREFIX
+ CONFIG_CUSTOM_CLASS_PROPERTY_NAME;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
import org.junit.platform.engine.UniqueId;
import org.junit.platform.engine.support.config.PrefixedConfigurationParameters;
import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter;
import org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService;
import org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine;
import org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutorService;
import org.junit.platform.engine.support.hierarchical.ParallelHierarchicalTestExecutorServiceFactory;
import org.junit.platform.engine.support.hierarchical.ThrowableCollector;

/**
Expand Down Expand Up @@ -79,8 +79,8 @@ public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId
protected HierarchicalTestExecutorService createExecutorService(ExecutionRequest request) {
JupiterConfiguration configuration = getJupiterConfiguration(request);
if (configuration.isParallelExecutionEnabled()) {
return new ForkJoinPoolHierarchicalTestExecutorService(new PrefixedConfigurationParameters(
request.getConfigurationParameters(), Constants.PARALLEL_CONFIG_PREFIX));
return ParallelHierarchicalTestExecutorServiceFactory.create(new PrefixedConfigurationParameters(
request.getConfigurationParameters(), JupiterConfiguration.PARALLEL_CONFIG_PREFIX));
}
return super.createExecutorService(request);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import static org.junit.jupiter.api.io.TempDir.DEFAULT_CLEANUP_MODE_PROPERTY_NAME;
import static org.junit.jupiter.api.io.TempDir.DEFAULT_FACTORY_PROPERTY_NAME;
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;
Expand Down Expand Up @@ -100,6 +102,17 @@ 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
Expand Down
Loading