|
15 | 15 | import static org.junit.vintage.engine.descriptor.VintageTestDescriptor.ENGINE_ID; |
16 | 16 |
|
17 | 17 | import java.util.Iterator; |
| 18 | +import java.util.List; |
18 | 19 | import java.util.Optional; |
| 20 | +import java.util.concurrent.CompletableFuture; |
| 21 | +import java.util.concurrent.CopyOnWriteArrayList; |
| 22 | +import java.util.concurrent.ExecutorService; |
| 23 | +import java.util.concurrent.Executors; |
| 24 | +import java.util.concurrent.TimeUnit; |
19 | 25 |
|
20 | 26 | import org.apiguardian.api.API; |
| 27 | +import org.junit.platform.commons.logging.Logger; |
| 28 | +import org.junit.platform.commons.logging.LoggerFactory; |
21 | 29 | import org.junit.platform.engine.EngineDiscoveryRequest; |
22 | 30 | import org.junit.platform.engine.EngineExecutionListener; |
23 | 31 | import org.junit.platform.engine.ExecutionRequest; |
|
37 | 45 | @API(status = INTERNAL, since = "4.12") |
38 | 46 | public final class VintageTestEngine implements TestEngine { |
39 | 47 |
|
| 48 | + private static final Logger logger = LoggerFactory.getLogger(VintageTestEngine.class); |
| 49 | + |
| 50 | + private static final int DEFAULT_THREAD_POOL_SIZE = 10; |
| 51 | + private static final int SHUTDOWN_TIMEOUT_SECONDS = 60; |
| 52 | + |
40 | 53 | @Override |
41 | 54 | public String getId() { |
42 | 55 | return ENGINE_ID; |
@@ -75,11 +88,64 @@ public void execute(ExecutionRequest request) { |
75 | 88 |
|
76 | 89 | private void executeAllChildren(VintageEngineDescriptor engineDescriptor, |
77 | 90 | EngineExecutionListener engineExecutionListener) { |
| 91 | + boolean parallelExecutionEnabled = getParallelExecutionEnabled(); |
| 92 | + |
| 93 | + if (parallelExecutionEnabled) { |
| 94 | + executeInParallel(engineDescriptor, engineExecutionListener); |
| 95 | + } |
| 96 | + else { |
| 97 | + executeSequentially(engineDescriptor, engineExecutionListener); |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + private void executeInParallel(VintageEngineDescriptor engineDescriptor, |
| 102 | + EngineExecutionListener engineExecutionListener) { |
| 103 | + ExecutorService executorService = Executors.newFixedThreadPool(getThreadPoolSize()); |
| 104 | + RunnerExecutor runnerExecutor = new RunnerExecutor(engineExecutionListener); |
| 105 | + |
| 106 | + List<TestDescriptor> children = new CopyOnWriteArrayList<>(engineDescriptor.getModifiableChildren()); |
| 107 | + |
| 108 | + CompletableFuture<Void> allOf = CompletableFuture.allOf( |
| 109 | + children.stream().map(descriptor -> CompletableFuture.runAsync(() -> { |
| 110 | + RunnerTestDescriptor testDescriptor = (RunnerTestDescriptor) descriptor; |
| 111 | + try { |
| 112 | + runnerExecutor.execute(testDescriptor); |
| 113 | + } |
| 114 | + catch (Exception e) { |
| 115 | + engineExecutionListener.executionSkipped(testDescriptor, e.getMessage()); |
| 116 | + } |
| 117 | + }, executorService)).toArray(CompletableFuture[]::new)); |
| 118 | + |
| 119 | + try { |
| 120 | + allOf.get(SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| 121 | + } |
| 122 | + catch (Exception e) { |
| 123 | + logger.warn(e, () -> "Timeout or interruption while waiting for parallel test execution to finish"); |
| 124 | + Thread.currentThread().interrupt(); |
| 125 | + } |
| 126 | + finally { |
| 127 | + executorService.shutdown(); |
| 128 | + } |
| 129 | + } |
| 130 | + |
| 131 | + private void executeSequentially(VintageEngineDescriptor engineDescriptor, |
| 132 | + EngineExecutionListener engineExecutionListener) { |
78 | 133 | RunnerExecutor runnerExecutor = new RunnerExecutor(engineExecutionListener); |
79 | | - for (Iterator<TestDescriptor> iterator = engineDescriptor.getModifiableChildren().iterator(); iterator.hasNext();) { |
| 134 | + Iterator<TestDescriptor> iterator = engineDescriptor.getModifiableChildren().iterator(); |
| 135 | + while (iterator.hasNext()) { |
80 | 136 | runnerExecutor.execute((RunnerTestDescriptor) iterator.next()); |
81 | 137 | iterator.remove(); |
82 | 138 | } |
83 | 139 | } |
84 | 140 |
|
| 141 | + private boolean getParallelExecutionEnabled() { |
| 142 | + // get parallel execution enabled from configuration |
| 143 | + return true; |
| 144 | + } |
| 145 | + |
| 146 | + private int getThreadPoolSize() { |
| 147 | + // get thread pool size from configuration |
| 148 | + return DEFAULT_THREAD_POOL_SIZE; |
| 149 | + } |
| 150 | + |
85 | 151 | } |
0 commit comments