-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Support parallelization in junit-vintage-engine #4135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
marcphilipp
merged 19 commits into
junit-team:main
from
YongGoose:feature/support-parallelization-in-junit-vintage-engine
Jan 8, 2025
Merged
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
e12b155
support parallelization in junit-vintage
YongGoose 96b31e0
Separate method for readability
YongGoose 56ea4b9
Merge branch 'main' into feature/support-parallelization-in-junit-vin…
YongGoose e0312cc
Add configuration parameter
YongGoose dfeb1cd
Stored the interrupted state in a local variable
YongGoose 190564c
Merge branch 'main' into feature/support-parallelization-in-junit-vin…
YongGoose 1a22c5c
Update junit-vintage-engine/src/main/java/org/junit/vintage/engine/Vi…
YongGoose f9af925
Remove try-catch
YongGoose b196388
Add integration test
YongGoose 0199187
Merge branch 'main' into feature/support-parallelization-in-junit-vin…
YongGoose 5ab051d
Check that test classes are executed concurrently
marcphilipp fc7b9c0
Add @API annotation and javadoc
YongGoose e572ab3
Write release-note and user-guide
YongGoose c7687fc
Merge branch 'main' into feature/support-parallelization-in-junit-vin…
YongGoose 52ec88b
Move constants to a new Constants class and mark as EXPERIMENTAL
YongGoose 5f9917b
Update copyright year
marcphilipp 2a6751a
Polish documentation
marcphilipp 7c4de20
Merge branch 'main' into feature/support-parallelization-in-junit-vin…
marcphilipp 4b4a60b
Revert "Update copyright year"
marcphilipp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
...e/src/test/java/org/junit/vintage/engine/execution/ParallelExecutionIntegrationTests.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| /* | ||
| * Copyright 2015-2024 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.vintage.engine.execution; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.junit.platform.testkit.engine.EventConditions.container; | ||
| import static org.junit.platform.testkit.engine.EventConditions.event; | ||
| import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully; | ||
| import static org.junit.platform.testkit.engine.EventConditions.started; | ||
| import static org.junit.vintage.engine.descriptor.VintageTestDescriptor.SEGMENT_TYPE_RUNNER; | ||
| import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.AbstractBlockingTestCase; | ||
| import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.FirstTestCase; | ||
| import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.ThirdTestCase; | ||
|
|
||
| import java.time.Instant; | ||
| import java.util.Arrays; | ||
| import java.util.HashSet; | ||
| import java.util.List; | ||
| import java.util.concurrent.CountDownLatch; | ||
|
|
||
| import org.assertj.core.api.Condition; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.junit.jupiter.api.TestReporter; | ||
| import org.junit.platform.engine.discovery.ClassSelector; | ||
| import org.junit.platform.engine.discovery.DiscoverySelectors; | ||
| import org.junit.platform.launcher.LauncherDiscoveryRequest; | ||
| import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; | ||
| import org.junit.platform.testkit.engine.EngineExecutionResults; | ||
| import org.junit.platform.testkit.engine.EngineTestKit; | ||
| import org.junit.platform.testkit.engine.Event; | ||
| import org.junit.platform.testkit.engine.Events; | ||
| import org.junit.vintage.engine.VintageTestEngine; | ||
| import org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.SecondTestCase; | ||
|
|
||
| class ParallelExecutionIntegrationTests { | ||
|
|
||
| private static final String PARALLEL_EXECUTION_ENABLED = "junit.vintage.execution.parallel.enabled"; | ||
| private static final String PARALLEL_POOL_SIZE = "junit.vintage.execution.parallel.pool-size"; | ||
marcphilipp marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| @Test | ||
| void executesTestClassesInParallel(TestReporter reporter) { | ||
| AbstractBlockingTestCase.threadNames.clear(); | ||
| AbstractBlockingTestCase.countDownLatch = new CountDownLatch(3); | ||
|
|
||
| var events = executeInParallelSuccessfully(3, FirstTestCase.class, SecondTestCase.class, | ||
| ThirdTestCase.class).list(); | ||
|
|
||
| var startedTimestamps = getTimestampsFor(events, event(container(SEGMENT_TYPE_RUNNER), started())); | ||
| var finishedTimestamps = getTimestampsFor(events, | ||
| event(container(SEGMENT_TYPE_RUNNER), finishedSuccessfully())); | ||
| var threadNames = new HashSet<>(AbstractBlockingTestCase.threadNames); | ||
|
|
||
| reporter.publishEntry("startedTimestamps", startedTimestamps.toString()); | ||
| reporter.publishEntry("finishedTimestamps", finishedTimestamps.toString()); | ||
|
|
||
| assertThat(startedTimestamps).hasSize(3); | ||
| assertThat(finishedTimestamps).hasSize(3); | ||
| assertThat(startedTimestamps).allMatch(startTimestamp -> finishedTimestamps.stream().noneMatch( | ||
| finishedTimestamp -> finishedTimestamp.isBefore(startTimestamp))); | ||
| assertThat(threadNames).hasSize(3); | ||
| } | ||
|
|
||
| private List<Instant> getTimestampsFor(List<Event> events, Condition<Event> condition) { | ||
| // @formatter:off | ||
| return events.stream() | ||
| .filter(condition::matches) | ||
| .map(Event::getTimestamp) | ||
| .toList(); | ||
| // @formatter:on | ||
| } | ||
|
|
||
| private Events executeInParallelSuccessfully(int poolSize, Class<?>... testClasses) { | ||
| var events = execute(poolSize, testClasses).allEvents(); | ||
| try { | ||
| return events.assertStatistics(it -> it.failed(0)); | ||
| } | ||
| catch (AssertionError error) { | ||
| events.debug(); | ||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| private static EngineExecutionResults execute(int poolSize, Class<?>... testClass) { | ||
| return EngineTestKit.execute(new VintageTestEngine(), request(poolSize, testClass)); | ||
| } | ||
|
|
||
| private static LauncherDiscoveryRequest request(int poolSize, Class<?>... testClasses) { | ||
| var classSelectors = Arrays.stream(testClasses) // | ||
| .map(DiscoverySelectors::selectClass) // | ||
| .toArray(ClassSelector[]::new); | ||
|
|
||
| return LauncherDiscoveryRequestBuilder.request() // | ||
| .selectors(classSelectors) // | ||
| .configurationParameter(PARALLEL_EXECUTION_ENABLED, String.valueOf(true)) // | ||
| .configurationParameter(PARALLEL_POOL_SIZE, String.valueOf(poolSize)) // | ||
| .build(); | ||
| } | ||
|
|
||
| } | ||
67 changes: 67 additions & 0 deletions
67
...src/testFixtures/java/org/junit/vintage/engine/samples/junit4/JUnit4ParallelTestCase.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| /* | ||
| * Copyright 2015-2024 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.vintage.engine.samples.junit4; | ||
|
|
||
| import static java.util.concurrent.TimeUnit.MILLISECONDS; | ||
|
|
||
| import java.util.Set; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.concurrent.CountDownLatch; | ||
|
|
||
| import org.junit.Rule; | ||
| import org.junit.Test; | ||
| import org.junit.experimental.runners.Enclosed; | ||
| import org.junit.rules.TestWatcher; | ||
| import org.junit.runner.Description; | ||
| import org.junit.runner.RunWith; | ||
|
|
||
| @RunWith(Enclosed.class) | ||
| public class JUnit4ParallelTestCase { | ||
|
|
||
| public static class AbstractBlockingTestCase { | ||
|
|
||
| public static final Set<String> threadNames = ConcurrentHashMap.newKeySet(); | ||
| public static CountDownLatch countDownLatch; | ||
|
|
||
| @Rule | ||
| public final TestWatcher testWatcher = new TestWatcher() { | ||
| @Override | ||
| protected void starting(Description description) { | ||
| AbstractBlockingTestCase.threadNames.add(Thread.currentThread().getName()); | ||
| } | ||
| }; | ||
|
|
||
| @Test | ||
| public void test() throws Exception { | ||
| countDownAndBlock(countDownLatch); | ||
| } | ||
|
|
||
| @SuppressWarnings("ResultOfMethodCallIgnored") | ||
| private static void countDownAndBlock(CountDownLatch countDownLatch) throws InterruptedException { | ||
| countDownLatch.countDown(); | ||
| countDownLatch.await(estimateSimulatedTestDurationInMilliseconds(), MILLISECONDS); | ||
| } | ||
|
|
||
| private static long estimateSimulatedTestDurationInMilliseconds() { | ||
| var runningInCi = Boolean.parseBoolean(System.getenv("CI")); | ||
| return runningInCi ? 1000 : 100; | ||
| } | ||
| } | ||
|
|
||
| public static class FirstTestCase extends AbstractBlockingTestCase { | ||
| } | ||
|
|
||
| public static class SecondTestCase extends AbstractBlockingTestCase { | ||
| } | ||
|
|
||
| public static class ThirdTestCase extends AbstractBlockingTestCase { | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.