Skip to content

Commit d178918

Browse files
committed
Introduce ConcurrentHierarchicalTestExecutorServiceFactory
1 parent fc59fc2 commit d178918

File tree

7 files changed

+141
-9
lines changed

7 files changed

+141
-9
lines changed

documentation/src/test/resources/junit-platform.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
junit.jupiter.execution.parallel.enabled=true
22
junit.jupiter.execution.parallel.mode.default=concurrent
3+
junit.jupiter.execution.parallel.config.executor-service=worker_thread_pool
34
junit.jupiter.execution.parallel.config.strategy=fixed
45
junit.jupiter.execution.parallel.config.fixed.parallelism=6
56

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import org.junit.jupiter.api.parallel.Execution;
3939
import org.junit.jupiter.engine.config.JupiterConfiguration;
4040
import org.junit.platform.commons.util.ClassNamePatternFilterUtils;
41+
import org.junit.platform.engine.support.hierarchical.ConcurrentHierarchicalTestExecutorServiceFactory;
42+
import org.junit.platform.engine.support.hierarchical.ConcurrentHierarchicalTestExecutorServiceFactory.ConcurrentExecutorServiceType;
4143
import org.junit.platform.engine.support.hierarchical.ParallelExecutionConfigurationStrategy;
4244

4345
/**
@@ -239,6 +241,22 @@ public final class Constants {
239241

240242
static final String PARALLEL_CONFIG_PREFIX = "junit.jupiter.execution.parallel.config.";
241243

244+
/**
245+
* Property name used to determine the desired
246+
* {@link ConcurrentExecutorServiceType ConcurrentExecutorServiceType}.
247+
*
248+
* <p>Value must be
249+
* {@link ConcurrentExecutorServiceType#FORK_JOIN_POOL FORK_JOIN_POOL} or
250+
* {@link ConcurrentExecutorServiceType#WORKER_THREAD_POOL WORKER_THREAD_POOL},
251+
* ignoring case.
252+
*
253+
* @since 6.1
254+
* @see ConcurrentHierarchicalTestExecutorServiceFactory
255+
*/
256+
@API(status = EXPERIMENTAL, since = "6.1")
257+
public static final String PARALLEL_CONFIG_EXECUTOR_SERVICE_PROPERTY_NAME = PARALLEL_CONFIG_PREFIX
258+
+ ConcurrentHierarchicalTestExecutorServiceFactory.EXECUTOR_SERVICE_PROPERTY_NAME;
259+
242260
/**
243261
* Property name used to select the
244262
* {@link ParallelExecutionConfigurationStrategy}: {@value}

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/JupiterTestEngine.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
import org.junit.platform.engine.UniqueId;
3030
import org.junit.platform.engine.support.config.PrefixedConfigurationParameters;
3131
import org.junit.platform.engine.support.discovery.DiscoveryIssueReporter;
32+
import org.junit.platform.engine.support.hierarchical.ConcurrentHierarchicalTestExecutorServiceFactory;
3233
import org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine;
3334
import org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutorService;
3435
import org.junit.platform.engine.support.hierarchical.ThrowableCollector;
35-
import org.junit.platform.engine.support.hierarchical.WorkerThreadPoolHierarchicalTestExecutorService;
3636

3737
/**
3838
* The JUnit Jupiter {@link org.junit.platform.engine.TestEngine TestEngine}.
@@ -79,7 +79,7 @@ public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId
7979
protected HierarchicalTestExecutorService createExecutorService(ExecutionRequest request) {
8080
JupiterConfiguration configuration = getJupiterConfiguration(request);
8181
if (configuration.isParallelExecutionEnabled()) {
82-
return new WorkerThreadPoolHierarchicalTestExecutorService(new PrefixedConfigurationParameters(
82+
return ConcurrentHierarchicalTestExecutorServiceFactory.create(new PrefixedConfigurationParameters(
8383
request.getConfigurationParameters(), Constants.PARALLEL_CONFIG_PREFIX));
8484
}
8585
return super.createExecutorService(request);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright 2015-2025 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package org.junit.platform.engine.support.hierarchical;
12+
13+
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
14+
15+
import java.util.Locale;
16+
17+
import org.apiguardian.api.API;
18+
import org.junit.platform.engine.ConfigurationParameters;
19+
import org.junit.platform.engine.support.config.PrefixedConfigurationParameters;
20+
21+
/**
22+
* Factory for {@link HierarchicalTestExecutorService} instances that support
23+
* concurrent execution.
24+
*
25+
* @since 6.1
26+
* @see ConcurrentExecutorServiceType
27+
* @see ForkJoinPoolHierarchicalTestExecutorService
28+
* @see WorkerThreadPoolHierarchicalTestExecutorService
29+
*/
30+
@API(status = EXPERIMENTAL, since = "6.1")
31+
public class ConcurrentHierarchicalTestExecutorServiceFactory {
32+
33+
/**
34+
* Property name used to determine the desired
35+
* {@link ConcurrentExecutorServiceType ConcurrentExecutorServiceType}.
36+
*
37+
* <p>Value must be
38+
* {@link ConcurrentExecutorServiceType#FORK_JOIN_POOL FORK_JOIN_POOL} or
39+
* {@link ConcurrentExecutorServiceType#WORKER_THREAD_POOL WORKER_THREAD_POOL},
40+
* ignoring case.
41+
*/
42+
public static final String EXECUTOR_SERVICE_PROPERTY_NAME = "executor-service";
43+
44+
/**
45+
* Create a new {@link HierarchicalTestExecutorService} based on the
46+
* supplied {@link ConfigurationParameters}.
47+
*
48+
* <p>This method is typically invoked with an instance of
49+
* {@link PrefixedConfigurationParameters} that was created with an
50+
* engine-specific prefix.
51+
*
52+
* <p>The {@value #EXECUTOR_SERVICE_PROPERTY_NAME} key is used to determine
53+
* which service implementation is to be used. Which other parameters are
54+
* read depends on the configured
55+
* {@link ParallelExecutionConfigurationStrategy} which is determined by the
56+
* {@value DefaultParallelExecutionConfigurationStrategy#CONFIG_STRATEGY_PROPERTY_NAME}
57+
* key.
58+
*
59+
* @see #EXECUTOR_SERVICE_PROPERTY_NAME
60+
* @see ConcurrentExecutorServiceType
61+
* @see ParallelExecutionConfigurationStrategy
62+
* @see PrefixedConfigurationParameters
63+
*/
64+
public static HierarchicalTestExecutorService create(ConfigurationParameters configurationParameters) {
65+
var executorServiceType = configurationParameters.get(EXECUTOR_SERVICE_PROPERTY_NAME,
66+
it -> ConcurrentExecutorServiceType.valueOf(it.toUpperCase(Locale.ROOT))) //
67+
.orElse(ConcurrentExecutorServiceType.FORK_JOIN_POOL);
68+
var configuration = DefaultParallelExecutionConfigurationStrategy.toConfiguration(configurationParameters);
69+
return create(executorServiceType, configuration);
70+
}
71+
72+
/**
73+
* Create a new {@link HierarchicalTestExecutorService} based on the
74+
* supplied {@link ConfigurationParameters}.
75+
*
76+
* @see ConcurrentExecutorServiceType
77+
* @see ParallelExecutionConfigurationStrategy
78+
*/
79+
public static HierarchicalTestExecutorService create(ConcurrentExecutorServiceType type,
80+
ParallelExecutionConfiguration configuration) {
81+
return switch (type) {
82+
case FORK_JOIN_POOL -> new ForkJoinPoolHierarchicalTestExecutorService(configuration);
83+
case WORKER_THREAD_POOL -> new WorkerThreadPoolHierarchicalTestExecutorService(configuration);
84+
};
85+
}
86+
87+
private ConcurrentHierarchicalTestExecutorServiceFactory() {
88+
}
89+
90+
/**
91+
* Type of {@link HierarchicalTestExecutorService} that supports concurrent
92+
* execution.
93+
*/
94+
public enum ConcurrentExecutorServiceType {
95+
96+
/**
97+
* Indicates that {@link ForkJoinPoolHierarchicalTestExecutorService}
98+
* should be used.
99+
*/
100+
FORK_JOIN_POOL,
101+
102+
/**
103+
* Indicates that {@link WorkerThreadPoolHierarchicalTestExecutorService}
104+
* should be used.
105+
*/
106+
WORKER_THREAD_POOL
107+
108+
}
109+
110+
}

junit-platform-engine/src/main/java/org/junit/platform/engine/support/hierarchical/WorkerThreadPoolHierarchicalTestExecutorService.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
import org.junit.platform.commons.util.ClassLoaderUtils;
5454
import org.junit.platform.commons.util.Preconditions;
5555
import org.junit.platform.commons.util.ToStringBuilder;
56-
import org.junit.platform.engine.ConfigurationParameters;
5756

5857
/**
5958
* @since 6.1
@@ -68,10 +67,6 @@ public class WorkerThreadPoolHierarchicalTestExecutorService implements Hierarch
6867
private final int parallelism;
6968
private final WorkerLeaseManager workerLeaseManager;
7069

71-
public WorkerThreadPoolHierarchicalTestExecutorService(ConfigurationParameters configurationParameters) {
72-
this(DefaultParallelExecutionConfigurationStrategy.toConfiguration(configurationParameters));
73-
}
74-
7570
public WorkerThreadPoolHierarchicalTestExecutorService(ParallelExecutionConfiguration configuration) {
7671
this(configuration, ClassLoaderUtils.getDefaultClassLoader());
7772
}

platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/ParallelExecutionIntegrationTests.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static org.junit.jupiter.api.parallel.ResourceAccessMode.READ_WRITE;
2222
import static org.junit.jupiter.engine.Constants.DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME;
2323
import static org.junit.jupiter.engine.Constants.DEFAULT_PARALLEL_EXECUTION_MODE;
24+
import static org.junit.jupiter.engine.Constants.PARALLEL_CONFIG_EXECUTOR_SERVICE_PROPERTY_NAME;
2425
import static org.junit.jupiter.engine.Constants.PARALLEL_CONFIG_FIXED_MAX_POOL_SIZE_PROPERTY_NAME;
2526
import static org.junit.jupiter.engine.Constants.PARALLEL_CONFIG_FIXED_PARALLELISM_PROPERTY_NAME;
2627
import static org.junit.jupiter.engine.Constants.PARALLEL_CONFIG_STRATEGY_PROPERTY_NAME;
@@ -74,12 +75,15 @@
7475
import org.junit.jupiter.api.parallel.Execution;
7576
import org.junit.jupiter.api.parallel.Isolated;
7677
import org.junit.jupiter.api.parallel.ResourceLock;
78+
import org.junit.jupiter.params.ParameterizedClass;
7779
import org.junit.jupiter.params.ParameterizedTest;
80+
import org.junit.jupiter.params.provider.EnumSource;
7881
import org.junit.jupiter.params.provider.ValueSource;
7982
import org.junit.platform.engine.DiscoverySelector;
8083
import org.junit.platform.engine.TestDescriptor;
8184
import org.junit.platform.engine.reporting.ReportEntry;
8285
import org.junit.platform.engine.support.descriptor.MethodSource;
86+
import org.junit.platform.engine.support.hierarchical.ConcurrentHierarchicalTestExecutorServiceFactory.ConcurrentExecutorServiceType;
8387
import org.junit.platform.testkit.engine.EngineExecutionResults;
8488
import org.junit.platform.testkit.engine.EngineTestKit;
8589
import org.junit.platform.testkit.engine.Event;
@@ -89,7 +93,9 @@
8993
* @since 1.3
9094
*/
9195
@SuppressWarnings({ "JUnitMalformedDeclaration", "NewClassNamingConvention" })
92-
class ParallelExecutionIntegrationTests {
96+
@ParameterizedClass
97+
@EnumSource(ConcurrentExecutorServiceType.class)
98+
record ParallelExecutionIntegrationTests(ConcurrentExecutorServiceType executorServiceType) {
9399

94100
@Test
95101
void successfulParallelTest(TestReporter reporter) {
@@ -579,11 +585,12 @@ private EngineExecutionResults executeWithFixedParallelism(int parallelism, Map<
579585
return executeWithFixedParallelism(parallelism, configParams, selectClasses(testClasses));
580586
}
581587

582-
private static EngineExecutionResults executeWithFixedParallelism(int parallelism, Map<String, String> configParams,
588+
private EngineExecutionResults executeWithFixedParallelism(int parallelism, Map<String, String> configParams,
583589
List<? extends DiscoverySelector> selectors) {
584590
return EngineTestKit.engine("junit-jupiter") //
585591
.selectors(selectors) //
586592
.configurationParameter(PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME, String.valueOf(true)) //
593+
.configurationParameter(PARALLEL_CONFIG_EXECUTOR_SERVICE_PROPERTY_NAME, executorServiceType.name()) //
587594
.configurationParameter(PARALLEL_CONFIG_STRATEGY_PROPERTY_NAME, "fixed") //
588595
.configurationParameter(PARALLEL_CONFIG_FIXED_PARALLELISM_PROPERTY_NAME, String.valueOf(parallelism)) //
589596
.configurationParameters(configParams) //

platform-tooling-support-tests/src/test/resources/junit-platform.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
junit.jupiter.execution.parallel.enabled=true
22
junit.jupiter.execution.parallel.mode.default=concurrent
3+
junit.jupiter.execution.parallel.config.executor-service=worker_thread_pool
34
junit.jupiter.execution.parallel.config.strategy=dynamic
45
junit.jupiter.execution.parallel.config.dynamic.factor=0.25
56
junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor=1

0 commit comments

Comments
 (0)