Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into saturate-via-property
Browse files Browse the repository at this point in the history
  • Loading branch information
mpkorstanje committed Oct 16, 2022
2 parents dccc0c7 + 2101806 commit d35e44c
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 29 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ task outputs from previous CI builds.
You need [JDK 17] to build JUnit 5. [Gradle toolchains] are used to detect and
potentially download additional JDKs for compilation and test execution.

Note: If you're working on a machine with an Apple Silicon processor, you'll need to
download and install a JDK 8 distribution manually (or via [SDKMAN!] or [asdf]) --
for example, one from [Zulu] or [Liberica].

All modules can be _built_ with the [Gradle Wrapper] using the following command.

`gradlew clean assemble`
Expand Down Expand Up @@ -92,6 +96,7 @@ See also <https://repo1.maven.org/maven2/org/junit/> for releases and
<https://oss.sonatype.org/content/repositories/snapshots/org/junit/> for snapshots.


[asdf]: https://asdf-vm.com/
[Codecov]: https://codecov.io/gh/junit-team/junit5
[CONTRIBUTING.md]: https://github.com/junit-team/junit5/blob/HEAD/CONTRIBUTING.md
[Dependency Metadata]: https://junit.org/junit5/docs/current/user-guide/#dependency-metadata
Expand All @@ -101,7 +106,10 @@ See also <https://repo1.maven.org/maven2/org/junit/> for releases and
[JaCoCo]: https://www.eclemma.org/jacoco/
[Javadoc]: https://junit.org/junit5/docs/current/api/
[JDK 17]: https://adoptium.net/archive.html?variant=openjdk17&jvmVariant=hotspot
[Liberica]: https://bell-sw.com/pages/downloads/
[Release Notes]: https://junit.org/junit5/docs/current/release-notes/
[Samples]: https://github.com/junit-team/junit5-samples
[SDKMAN!]: https://sdkman.io/jdks
[StackOverflow]: https://stackoverflow.com/questions/tagged/junit5
[User Guide]: https://junit.org/junit5/docs/current/user-guide/
[Zulu]: https://www.azul.com/downloads/?version=java-8-lts&os=macos&architecture=arm-64-bit&package=jdk#download-openjdk
6 changes: 3 additions & 3 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
`kotlin-dsl`
id("com.github.ben-manes.versions") version "0.39.0"
id("com.github.ben-manes.versions") version "0.42.0"
}

repositories {
Expand All @@ -12,8 +12,8 @@ repositories {
dependencies {
implementation(kotlin("gradle-plugin"))
implementation("biz.aQute.bnd:biz.aQute.bnd.gradle:6.3.1")
implementation("com.diffplug.spotless:spotless-plugin-gradle:6.0.0")
implementation("com.github.ben-manes:gradle-versions-plugin:0.39.0")
implementation("com.diffplug.spotless:spotless-plugin-gradle:6.11.0")
implementation("com.github.ben-manes:gradle-versions-plugin:0.42.0")
implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.2")
implementation("org.gradle:test-retry-gradle-plugin:1.4.1")
compileOnly("com.gradle:gradle-enterprise-gradle-plugin:3.11.1") // keep in sync with root settings.gradle.kts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ GitHub.

==== Bug Fixes

*
* Fixed fallback to ForkJoinPools Java 7 constructor on Java 9 and higher

==== Deprecations and Breaking Changes

Expand All @@ -25,6 +25,7 @@ GitHub.

* Support limiting the number of concurrently executing tests via a property


[[release-notes-5.10.0-M1️-junit-jupiter]]
=== JUnit Jupiter

Expand All @@ -44,6 +45,11 @@ GitHub.
* Added the `junit.jupiter.execution.parallel.config.fixed.saturate` configuration
property.

==== New Features and Improvements

* ❓


[[release-notes-5.10.0-M1️-junit-vintage]]
=== JUnit Vintage

Expand Down
22 changes: 11 additions & 11 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,46 @@ asciidoctor-pdf = "1.5.3"
assertj = "3.23.1"
checkstyle = "9.0"
jacoco = "0.8.7"
jmh = "1.33"
jmh = "1.35"
junit4 = "4.13.2"
junit4Osgi = "4.13.2_1"
junit4Min = "4.12"
ktlint = "0.43.0"
log4j = "2.17.1"
log4j = "2.19.0"
opentest4j = "1.2.0"
openTestReporting = "0.1.0-M1"
surefire = "2.22.2"
xmlunit = "2.8.4"
xmlunit = "2.9.0"

[libraries]
ant = { module = "org.apache.ant:ant", version.ref = "ant" }
ant-junit = { module = "org.apache.ant:ant-junit", version.ref = "ant" }
ant-junitlauncher = { module = "org.apache.ant:ant-junitlauncher", version.ref = "ant" }
apiguardian = { module = "org.apiguardian:apiguardian-api", version.ref = "apiguardian" }
archunit = { module = "com.tngtech.archunit:archunit-junit5", version = "0.23.1" }
archunit = { module = "com.tngtech.archunit:archunit-junit5", version = "1.0.0" }
assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" }
bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" }
bnd = { module = "biz.aQute.bnd:biz.aQute.bndlib", version = "6.3.1" }
classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.132" }
classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.149" }
commons-io = { module = "commons-io:commons-io", version = "2.11.0" }
groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.1" }
groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.5" }
groovy2-bom = { module = "org.codehaus.groovy:groovy-bom", version = "2.5.14" }
hamcrest = { module = "org.hamcrest:hamcrest", version = "2.2" }
jfrunit = { module = "org.moditect.jfrunit:jfrunit-core", version = "1.0.0.Alpha2" }
jmh-core = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" }
jmh-generator-annprocess = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.ref = "jmh" }
joox = { module = "org.jooq:joox", version = "1.6.2" }
junit4 = { module = "junit:junit", version = { require = "[4.12,)", prefer = "4.13.2" } }
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.4.3" }
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.6.4" }
log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" }
log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4j" }
maven = { module = "org.apache.maven:apache-maven", version = "3.8.5" }
mockito = { module = "org.mockito:mockito-junit-jupiter", version = "4.1.0" }
maven = { module = "org.apache.maven:apache-maven", version = "3.8.6" }
mockito = { module = "org.mockito:mockito-junit-jupiter", version = "4.8.0" }
opentest4j = { module = "org.opentest4j:opentest4j", version.ref = "opentest4j" }
openTestReporting-events = { module = "org.opentest4j.reporting:open-test-reporting-events", version.ref = "openTestReporting" }
openTestReporting-tooling = { module = "org.opentest4j.reporting:open-test-reporting-tooling", version.ref = "openTestReporting" }
picocli = { module = "info.picocli:picocli", version = "4.6.2" }
slf4j-julBinding = { module = "org.slf4j:slf4j-jdk14", version = "1.7.32" }
picocli = { module = "info.picocli:picocli", version = "4.6.3" }
slf4j-julBinding = { module = "org.slf4j:slf4j-jdk14", version = "2.0.3" }
spock1 = { module = "org.spockframework:spock-core", version = "1.3-groovy-2.5" }
univocity-parsers = { module = "com.univocity:univocity-parsers", version = "2.9.1" }
xmlunit-assertj = { module = "org.xmlunit:xmlunit-assertj3", version.ref = "xmlunit" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;

import org.apiguardian.api.API;
Expand Down Expand Up @@ -81,18 +84,32 @@ private static ParallelExecutionConfiguration createConfiguration(ConfigurationP

private ForkJoinPool createForkJoinPool(ParallelExecutionConfiguration configuration) {
ForkJoinWorkerThreadFactory threadFactory = new WorkerThreadFactory();
return Try.call(() -> {
// Try to use constructor available in Java >= 9
Constructor<ForkJoinPool> constructor = ForkJoinPool.class.getDeclaredConstructor(Integer.TYPE,
ForkJoinWorkerThreadFactory.class, UncaughtExceptionHandler.class, Boolean.TYPE, Integer.TYPE,
Integer.TYPE, Integer.TYPE, Predicate.class, Long.TYPE, TimeUnit.class);
return constructor.newInstance(configuration.getParallelism(), threadFactory, null, false,
configuration.getCorePoolSize(), configuration.getMaxPoolSize(), configuration.getMinimumRunnable(),
configuration.getSaturatePredicate(), configuration.getKeepAliveSeconds(), TimeUnit.SECONDS);
}).orElseTry(() -> {
// Fallback for Java 8
return new ForkJoinPool(configuration.getParallelism(), threadFactory, null, false);
}).getOrThrow(cause -> new JUnitException("Failed to create ForkJoinPool", cause));
// Try to use constructor available in Java >= 9
Callable<ForkJoinPool> constructorInvocation = sinceJava9Constructor() //
.map(sinceJava9ConstructorInvocation(configuration, threadFactory))
// Fallback for Java 8
.orElse(sinceJava7ConstructorInvocation(configuration, threadFactory));
return Try.call(constructorInvocation) //
.getOrThrow(cause -> new JUnitException("Failed to create ForkJoinPool", cause));
}

private static Optional<Constructor<ForkJoinPool>> sinceJava9Constructor() {
return Try.call(() -> ForkJoinPool.class.getDeclaredConstructor(Integer.TYPE, ForkJoinWorkerThreadFactory.class,
UncaughtExceptionHandler.class, Boolean.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE, Predicate.class,
Long.TYPE, TimeUnit.class)) //
.toOptional();
}

private static Function<Constructor<ForkJoinPool>, Callable<ForkJoinPool>> sinceJava9ConstructorInvocation(
ParallelExecutionConfiguration configuration, ForkJoinWorkerThreadFactory threadFactory) {
return constructor -> () -> constructor.newInstance(configuration.getParallelism(), threadFactory, null, false,
configuration.getCorePoolSize(), configuration.getMaxPoolSize(), configuration.getMinimumRunnable(),
configuration.getSaturatePredicate(), configuration.getKeepAliveSeconds(), TimeUnit.SECONDS);
}

private static Callable<ForkJoinPool> sinceJava7ConstructorInvocation(ParallelExecutionConfiguration configuration,
ForkJoinWorkerThreadFactory threadFactory) {
return () -> new ForkJoinPool(configuration.getParallelism(), threadFactory, null, false);
}

@Override
Expand Down Expand Up @@ -199,6 +216,7 @@ static class WorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFac
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return new WorkerThread(pool, contextClassLoader);
}

}

static class WorkerThread extends ForkJoinWorkerThread {
Expand All @@ -207,6 +225,7 @@ static class WorkerThread extends ForkJoinWorkerThread {
super(pool);
setContextClassLoader(contextClassLoader);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
* {@link #testPlanExecutionStarted(TestPlan)} and
* {@link #testPlanExecutionFinished(TestPlan)}.
*
* <p>Note on concurrency: {@link #testPlanExecutionStarted(TestPlan)} and
* {@link #testPlanExecutionFinished(TestPlan)} are always called from the same
* thread. It is safe to assume that there is at most one {@code TestPlan}
* instance at a time. All other methods could be called from different threads
* concurrently in case one or multiple test engines execute tests in parallel.
*
* @since 1.0
* @see Launcher
* @see TestPlan
Expand All @@ -58,6 +64,8 @@ public interface TestExecutionListener {
* Called when the execution of the {@link TestPlan} has started,
* <em>before</em> any test has been executed.
*
* <p>Called from the same thread as {@link #testPlanExecutionFinished(TestPlan)}.
*
* @param testPlan describes the tree of tests about to be executed
*/
default void testPlanExecutionStarted(TestPlan testPlan) {
Expand All @@ -67,6 +75,8 @@ default void testPlanExecutionStarted(TestPlan testPlan) {
* Called when the execution of the {@link TestPlan} has finished,
* <em>after</em> all tests have been executed.
*
* <p>Called from the same thread as {@link #testPlanExecutionStarted(TestPlan)}.
*
* @param testPlan describes the tree of tests that have been executed
*/
default void testPlanExecutionFinished(TestPlan testPlan) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2015-2022 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.platform.engine.support.hierarchical;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.commons.JUnitException;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class ForkJoinPoolHierarchicalTestExecutorServiceTests {

@Mock
ParallelExecutionConfiguration configuration;

@Test
void exceptionsFromInvalidConfigurationAreNotSwallowed() {
when(configuration.getParallelism()).thenReturn(2);
when(configuration.getMaxPoolSize()).thenReturn(1); // invalid, should be > parallelism
when(configuration.getCorePoolSize()).thenReturn(1);
when(configuration.getMinimumRunnable()).thenReturn(1);
when(configuration.getSaturatePredicate()).thenReturn(__ -> true);
when(configuration.getKeepAliveSeconds()).thenReturn(0);

JUnitException exception = assertThrows(JUnitException.class,
() -> new ForkJoinPoolHierarchicalTestExecutorService(configuration));
assertThat(exception).hasMessage("Failed to create ForkJoinPool");
assertThat(exception).rootCause().isInstanceOf(IllegalArgumentException.class);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ dependencies {
}
}

val unzipMavenDistribution by tasks.registering(Copy::class) {
val unzipMavenDistribution by tasks.registering(Sync::class) {
from(zipTree(mavenDistribution.elements.map { it.single() }))
into(layout.buildDirectory.dir("maven-distribution"))
}
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pluginManagement {
// Check if workaround in documentation.gradle.kts can be removed when upgrading
id("org.asciidoctor.jvm.convert") version "3.3.2"
id("org.asciidoctor.jvm.pdf") version "3.3.2"
id("me.champeau.jmh") version "0.6.6"
id("me.champeau.jmh") version "0.6.8"
id("io.spring.nohttp") version "0.0.10"
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
}
Expand Down

0 comments on commit d35e44c

Please sign in to comment.