This is an automated email from the ASF dual-hosted git repository.
ibessonov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new bc465f5 IGNITE-15543 Support injecting static variables with the
WorkDirectory extension (#357)
bc465f5 is described below
commit bc465f5b2a8877efb08ad5ef39d2a861b53f021b
Author: Alexander Polovtcev <[email protected]>
AuthorDate: Thu Sep 30 15:42:33 2021 +0300
IGNITE-15543 Support injecting static variables with the WorkDirectory
extension (#357)
---
.../CheckUnusedDependenciesAndPluginsInParent.sh | 2 +-
modules/core/pom.xml | 6 +
.../testframework/SystemPropertiesExtension.java | 45 +---
.../internal/testframework/WithSystemProperty.java | 22 +-
.../testframework/WorkDirectoryExtension.java | 113 +++++---
.../testframework/WorkDirectoryExtensionTest.java | 293 +++++++++++++++++++++
parent/pom.xml | 24 +-
7 files changed, 415 insertions(+), 90 deletions(-)
diff --git
a/check-rules/maven-check-scripts/CheckUnusedDependenciesAndPluginsInParent.sh
b/check-rules/maven-check-scripts/CheckUnusedDependenciesAndPluginsInParent.sh
index 02d2382..1c5a15a 100644
---
a/check-rules/maven-check-scripts/CheckUnusedDependenciesAndPluginsInParent.sh
+++
b/check-rules/maven-check-scripts/CheckUnusedDependenciesAndPluginsInParent.sh
@@ -17,7 +17,7 @@ set -o nounset; set -o errexit; set -o pipefail; set -o
errtrace; set -o functra
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )/../.."
POMS=$(find ${ROOT} -name pom.xml | grep -v parent)
-for xpath in
"project/dependencyManagement/dependencies/dependency/artifactId/text()" \
+for xpath in
"project/dependencyManagement/dependencies/dependency[not(scope='import')]/artifactId/text()"
\
"project/build/pluginManagement/plugins/plugin/artifactId/text()"; do
xpath -q -e "${xpath}" ${ROOT}/parent/pom.xml | \
while read -r declaration; do
diff --git a/modules/core/pom.xml b/modules/core/pom.xml
index a869550..71c0145 100644
--- a/modules/core/pom.xml
+++ b/modules/core/pom.xml
@@ -57,6 +57,12 @@
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-testkit</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/testframework/SystemPropertiesExtension.java
b/modules/core/src/test/java/org/apache/ignite/internal/testframework/SystemPropertiesExtension.java
index a1c9caa..5e4db6e 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/testframework/SystemPropertiesExtension.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/testframework/SystemPropertiesExtension.java
@@ -29,7 +29,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
/**
- * JUnit rule that manages usage of {@link WithSystemProperty}
annotations.<br/>
+ * JUnit rule that manages usage of {@link WithSystemProperty} annotations.<br>
* Should be used in {@link ExtendWith}.
*
* @see WithSystemProperty
@@ -37,7 +37,7 @@ import org.junit.jupiter.api.extension.ExtensionContext;
*/
public class SystemPropertiesExtension implements
BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback
{
- /** Class properties. */
+ /** Method properties. */
@SuppressWarnings("InstanceVariableMayNotBeInitialized")
private List<Prop<String, String>> testMethodSysProps;
@@ -75,26 +75,20 @@ public class SystemPropertiesExtension implements
* @param testCls Current test class.
* @return List of updated properties in reversed order.
*/
- private List<Prop<String, String>>
extractSystemPropertiesBeforeClass(Class<?> testCls) {
+ private static List<Prop<String, String>>
extractSystemPropertiesBeforeClass(Class<?> testCls) {
List<WithSystemProperty[]> allProps = new ArrayList<>();
for (Class<?> cls = testCls; cls != null; cls = cls.getSuperclass()) {
- SystemPropertiesList clsProps =
cls.getAnnotation(SystemPropertiesList.class);
-
- if (clsProps != null)
- allProps.add(clsProps.value());
- else {
- WithSystemProperty clsProp =
cls.getAnnotation(WithSystemProperty.class);
+ WithSystemProperty[] props =
cls.getAnnotationsByType(WithSystemProperty.class);
- if (clsProp != null)
- allProps.add(new WithSystemProperty[] {clsProp});
- }
+ if (props.length > 0)
+ allProps.add(props);
}
Collections.reverse(allProps);
// List of system properties to set when all tests in class are
finished.
- final List<Prop<String, String>> clsSysProps = new ArrayList<>();
+ List<Prop<String, String>> clsSysProps = new ArrayList<>();
for (WithSystemProperty[] props : allProps) {
for (WithSystemProperty prop : props) {
@@ -115,29 +109,16 @@ public class SystemPropertiesExtension implements
* @param testMtd Current test method.
* @return List of updated properties in reversed order.
*/
- public List<Prop<String, String>>
extractSystemPropertiesBeforeTestMethod(Method testMtd) {
- WithSystemProperty[] allProps = null;
-
- SystemPropertiesList testProps =
testMtd.getAnnotation(SystemPropertiesList.class);
-
- if (testProps != null)
- allProps = testProps.value();
- else {
- WithSystemProperty testProp =
testMtd.getAnnotation(WithSystemProperty.class);
-
- if (testProp != null)
- allProps = new WithSystemProperty[] {testProp};
- }
+ private static List<Prop<String, String>>
extractSystemPropertiesBeforeTestMethod(Method testMtd) {
+ WithSystemProperty[] allProps =
testMtd.getAnnotationsByType(WithSystemProperty.class);
// List of system properties to set when test is finished.
List<Prop<String, String>> testSysProps = new ArrayList<>();
- if (allProps != null) {
- for (WithSystemProperty prop : allProps) {
- String oldVal = System.setProperty(prop.key(), prop.value());
+ for (WithSystemProperty prop : allProps) {
+ String oldVal = System.setProperty(prop.key(), prop.value());
- testSysProps.add(new Prop<>(prop.key(), oldVal));
- }
+ testSysProps.add(new Prop<>(prop.key(), oldVal));
}
Collections.reverse(testSysProps);
@@ -150,7 +131,7 @@ public class SystemPropertiesExtension implements
*
* @param sysProps List of properties to clear.
*/
- private void clearSystemProperties(List<Prop<String, String>> sysProps) {
+ private static void clearSystemProperties(List<Prop<String, String>>
sysProps) {
if (sysProps == null)
return; // Nothing to do.
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/testframework/WithSystemProperty.java
b/modules/core/src/test/java/org/apache/ignite/internal/testframework/WithSystemProperty.java
index 24407ff..9f8102c 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/testframework/WithSystemProperty.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/testframework/WithSystemProperty.java
@@ -26,12 +26,12 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
/**
- * Annotation that defines a scope with specific system property
configured.<br/>
- * <br/>
- * Might be used on class level or on method level. Multiple annotations might
be applied to the same class/method.<br/>
- * <br/>
- * In short, these two approaches are basically equivalent:<br/>
- * <br/>
+ * Annotation that defines a scope with specific system property
configured.<br>
+ * <br>
+ * Might be used on class level or on method level. Multiple annotations might
be applied to the same class/method.<br>
+ * <br>
+ * In short, these two approaches are basically equivalent:<br>
+ * <br>
* Short:
* <pre>{@code @WithSystemProperty(key = "name", value = "val")
* public class SomeTest {
@@ -60,7 +60,7 @@ import org.junit.jupiter.api.BeforeEach;
* <p>
* Same applies to methods with the difference that annotation translates into
something like {@link BeforeEach} and
* {@link AfterEach}.
- * <br/><br/>
+ * <br><br>
* <pre>{@code public class SomeTest {
* @Test
* @WithSystemProperty(key = "name", value = "val")
@@ -89,10 +89,10 @@ import org.junit.jupiter.api.BeforeEach;
* }</pre>
* For class level annotation it applies system properties for the whole class
hierarchy (ignoring interfaces, there's
* no linearization implemented). More specific classes have higher priority
and set their properties last. It all
- * starts with {@link Object} which, of course, is not annotated.<br/>
- * <br/>
- * Test methods do not inherit their annotations from overridden methods of
super class.<br/>
- * <br/>
+ * starts with {@link Object} which, of course, is not annotated.<br>
+ * <br>
+ * Test methods do not inherit their annotations from overridden methods of
super class.<br>
+ * <br>
* If more than one annotation is presented on class/method then they will be
applied in the same order as they
* appear in code. It is achieved with the help of {@link Repeatable} feature
of Java annotations -
* {@link SystemPropertiesList} is automatically generated in such cases.
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtension.java
b/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtension.java
index 54791a9..0423dd0 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtension.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtension.java
@@ -19,13 +19,19 @@ package org.apache.ignite.internal.testframework;
import java.io.IOException;
import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
+import java.util.stream.Stream;
import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.lang.IgniteSystemProperties;
import org.jetbrains.annotations.Nullable;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
@@ -34,20 +40,33 @@ import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.platform.commons.support.AnnotationSupport;
import org.junit.platform.commons.support.HierarchyTraversalMode;
+import static org.junit.jupiter.api.extension.ExtensionContext.Namespace;
+
/**
* JUnit extension for injecting temporary folders into test classes.
* <p>
* This extension supports both field and parameter injection of {@link Path}
parameters annotated with the
* {@link WorkDirectory} annotation.
* <p>
- * A new temporary folder is created for every test method and will be located
relative to the module,
- * where the tests are being run, by the following path:
- * "target/work/{@literal
<name-of-the-test-class>/<name-of-the-test-method>_<current_time_millis>}".
- * It is removed after a test has finished running, but this behaviour can be
controlled by setting the
+ * A new temporary folder can be created for every test method (when used as a
test parameter or as a member field)
+ * or a single time in a test class' lifetime (when used as a parameter in a
{@link BeforeAll} hook or as a static
+ * field). Temporary folders are located relative to the module, where the
tests are being run, and their paths depends
+ * on the lifecycle of the folder:
+ *
+ * <ol>
+ * <li>For test methods: "target/work/{@literal
<name-of-the-test-class>/<name-of-the-test-method>_<current_time_millis>}"</li>
+ * <li>For test classes: "target/work/{@literal
<name-of-the-test-class>/static_<current_time_millis>}"</li>
+ * </ol>
+ *
+ * Temporary folders are removed after tests have finished running, but this
behaviour can be controlled by setting the
* {@link WorkDirectoryExtension#KEEP_WORK_DIR_PROPERTY} property to {@code
true}, in which case the created folder can
* be kept intact for debugging purposes.
*/
-public class WorkDirectoryExtension implements BeforeEachCallback,
AfterEachCallback, ParameterResolver {
+public class WorkDirectoryExtension
+ implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback,
AfterEachCallback, ParameterResolver {
+ /** JUnit namespace for the extension. */
+ private static final Namespace NAMESPACE =
Namespace.create(WorkDirectoryExtension.class);
+
/**
* System property that, when set to {@code true}, will make the extension
preserve the created directories.
* Default is {@code false}.
@@ -57,31 +76,60 @@ public class WorkDirectoryExtension implements
BeforeEachCallback, AfterEachCall
/** Base path for all temporary folders in a module. */
private static final Path BASE_PATH = Path.of("target", "work");
+ /** Name of the work directory that will be injected into {@link
BeforeAll} methods or static members. */
+ private static final String STATIC_FOLDER_NAME = "static";
+
+ /**
+ * Creates and injects a temporary directory into a static field.
+ */
+ @Override public void beforeAll(ExtensionContext context) throws Exception
{
+ Field workDirField = getWorkDirField(context);
+
+ if (workDirField == null ||
!Modifier.isStatic(workDirField.getModifiers()))
+ return;
+
+ workDirField.setAccessible(true);
+
+ workDirField.set(null, createWorkDir(context));
+ }
+
/** {@inheritDoc} */
- @Override public void beforeEach(ExtensionContext context) throws
Exception {
- Object testInstance = context.getRequiredTestInstance();
+ @Override public void afterAll(ExtensionContext context) throws Exception {
+ try (Stream<Path> list = Files.list(BASE_PATH)) {
+ if (list.findAny().isEmpty())
+ IgniteUtils.deleteIfExists(BASE_PATH);
+ }
+ }
- Field workDirField = getWorkDirField(testInstance.getClass());
+ /**
+ * Creates and injects a temporary directory into a field.
+ */
+ @Override public void beforeEach(ExtensionContext context) throws
Exception {
+ Field workDirField = getWorkDirField(context);
- if (workDirField == null)
+ if (workDirField == null ||
Modifier.isStatic(workDirField.getModifiers()))
return;
workDirField.setAccessible(true);
- workDirField.set(testInstance, createWorkDir(context));
+ workDirField.set(context.getRequiredTestInstance(),
createWorkDir(context));
}
/** {@inheritDoc} */
@Override public void afterEach(ExtensionContext context) throws Exception
{
- if (shouldRemoveDir())
- IgniteUtils.deleteIfExists(BASE_PATH);
+ if (shouldRemoveDir()) {
+ Path workDir =
context.getStore(NAMESPACE).get(context.getUniqueId(), Path.class);
+
+ if (workDir != null)
+ IgniteUtils.deleteIfExists(workDir);
+ }
}
/** {@inheritDoc} */
@Override public boolean supportsParameter(
ParameterContext parameterContext, ExtensionContext extensionContext
) throws ParameterResolutionException {
- return getParameterType(parameterContext).equals(Path.class)
+ return parameterContext.getParameter().getType().equals(Path.class)
&& parameterContext.isAnnotated(WorkDirectory.class);
}
@@ -89,6 +137,12 @@ public class WorkDirectoryExtension implements
BeforeEachCallback, AfterEachCall
@Override public Object resolveParameter(
ParameterContext parameterContext, ExtensionContext extensionContext
) throws ParameterResolutionException {
+ if (getWorkDirField(extensionContext) != null) {
+ throw new IllegalStateException(
+ "Cannot perform parameter injection, because there exists a
field annotated with @WorkDirectory"
+ );
+ }
+
try {
return createWorkDir(extensionContext);
}
@@ -98,40 +152,39 @@ public class WorkDirectoryExtension implements
BeforeEachCallback, AfterEachCall
}
/**
- * Shortcut for extracting the method parameter type from a {@link
ParameterContext}.
+ * Creates a temporary folder for the given test method.
*/
- private static Class<?> getParameterType(ParameterContext
parameterContext) {
- return parameterContext.getParameter().getType();
- }
+ private static Path createWorkDir(ExtensionContext context) throws
IOException {
+ Path existingDir =
context.getStore(NAMESPACE).get(context.getUniqueId(), Path.class);
- /**
- * Creates the temporary folder for the given test method.
- */
- private static Path createWorkDir(ExtensionContext extensionContext)
throws IOException {
- if (shouldRemoveDir())
- IgniteUtils.deleteIfExists(BASE_PATH);
+ if (existingDir != null)
+ return existingDir;
- String testClassDir =
extensionContext.getRequiredTestClass().getSimpleName();
+ String testClassDir = context.getRequiredTestClass().getSimpleName();
- String testMethodDir =
extensionContext.getRequiredTestMethod().getName() + '_' +
System.currentTimeMillis();
+ String testMethodDir = context.getTestMethod()
+ .map(Method::getName)
+ .orElse(STATIC_FOLDER_NAME);
- Path workDir = BASE_PATH.resolve(testClassDir).resolve(testMethodDir);
+ Path workDir = BASE_PATH.resolve(testClassDir).resolve(testMethodDir +
'_' + System.currentTimeMillis());
Files.createDirectories(workDir);
+ context.getStore(NAMESPACE).put(context.getUniqueId(), workDir);
+
return workDir;
}
/**
* Looks for the annotated field inside the given test class.
*
- * @return annotated field or {@code null} if no fields have been found
- * @throws IllegalStateException if more than one annotated fields have
been found
+ * @return Annotated field or {@code null} if no fields have been found
+ * @throws IllegalStateException If more than one annotated fields have
been found
*/
@Nullable
- private static Field getWorkDirField(Class<?> testClass) {
+ private static Field getWorkDirField(ExtensionContext context) {
List<Field> fields = AnnotationSupport.findAnnotatedFields(
- testClass,
+ context.getRequiredTestClass(),
WorkDirectory.class,
field -> field.getType().equals(Path.class),
HierarchyTraversalMode.TOP_DOWN
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtensionTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtensionTest.java
new file mode 100644
index 0000000..911627a
--- /dev/null
+++
b/modules/core/src/test/java/org/apache/ignite/internal/testframework/WorkDirectoryExtensionTest.java
@@ -0,0 +1,293 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.testframework;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.RepeatedTest;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.platform.testkit.engine.EngineExecutionResults;
+import org.junit.platform.testkit.engine.EngineTestKit;
+import org.junit.platform.testkit.engine.EventType;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import static
org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
+import static
org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully;
+import static
org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
+import static org.junit.platform.testkit.engine.EventConditions.type;
+import static
org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf;
+import static
org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
+
+/**
+ * Tests for the {@link WorkDirectoryExtension}.
+ * <p>
+ * This class uses an approach when several nested classes are executed
manually on the JUnit test engine, because
+ * some test methods should fail as part of these meta-tests. Nested classes
are skipped by the surefire plugin
+ * and must not be executed during the build.
+ *
+ * @see <a
href="https://junit.org/junit5/docs/current/user-guide/#testkit">JUnit Platform
Test Kit</a>
+ */
+public class WorkDirectoryExtensionTest {
+
+ /**
+ * Test class for the {@link #testStaticFieldInjection()} test.
+ */
+ @ExtendWith(WorkDirectoryExtension.class)
+ static class NormalStaticFieldInjectionTest {
+ /** */
+ @WorkDirectory
+ private static Path workDir;
+
+ /** */
+ private static Path testFile;
+
+ /** */
+ @BeforeAll
+ static void beforeAll() throws IOException {
+ testFile = Files.createFile(workDir.resolve("foo"));
+ }
+
+ /** */
+ @RepeatedTest(3)
+ public void test() {
+ assertTrue(Files.exists(testFile));
+ }
+ }
+
+ /**
+ * Tests temporary folder injection into a static field by running a test
multiple times and checking
+ * that the folder persists between the runs.
+ */
+ @Test
+ void testStaticFieldInjection() {
+ assertExecutesSuccessfully(NormalStaticFieldInjectionTest.class);
+ }
+
+ /**
+ * Test class for the {@link #testFieldInjection()} test.
+ */
+ @ExtendWith(WorkDirectoryExtension.class)
+ static class NormalFieldInjectionTest {
+ /** */
+ private static final Set<Path> paths = new HashSet<>();
+
+ /** */
+ @WorkDirectory
+ private Path workDir;
+
+ /** */
+ @RepeatedTest(3)
+ public void test() {
+ assertThat(paths, not(contains(workDir)));
+
+ for (Path path : paths)
+ assertTrue(Files.notExists(path));
+
+ paths.add(workDir);
+ }
+ }
+
+ /**
+ * Tests temporary folder injection into a field by running a test
multiple times and checking
+ * that a new folder is created each time.
+ */
+ @Test
+ void testFieldInjection() {
+ assertExecutesSuccessfully(NormalFieldInjectionTest.class);
+ }
+
+ /**
+ * Test class for the {@link #testMultipleMethodsInjection()} test.
+ */
+ @ExtendWith(WorkDirectoryExtension.class)
+ static class MultipleMethodsInjectionTest {
+ /** */
+ @BeforeEach
+ void setUp(@WorkDirectory Path workDir) throws IOException {
+ Files.createFile(workDir.resolve("foo"));
+ }
+
+ /** */
+ @Test
+ void test(@WorkDirectory Path workDir) {
+ assertTrue(Files.exists(workDir.resolve("foo")));
+ }
+ }
+
+ /**
+ * Tests a scenario when a folder is injected into both {@code BeforeEach}
and test method and checks that it is
+ * the same folder, and it does not get re-created.
+ */
+ @Test
+ void testMultipleMethodsInjection() {
+ assertExecutesSuccessfully(MultipleMethodsInjectionTest.class);
+ }
+
+ /**
+ * Test class for the {@link #testDuplicateFieldAndParameterInjection()}
test.
+ */
+ @ExtendWith(WorkDirectoryExtension.class)
+ static class ErrorParameterResolutionTest {
+ /** */
+ @WorkDirectory
+ private static Path workDir;
+
+ /** */
+ @BeforeEach
+ void setUp(@WorkDirectory Path anotherWorkDir) {
+ fail("Should not reach here");
+ }
+
+ /** */
+ @Test
+ public void test() {
+ fail("Should not reach here");
+ }
+ }
+
+ /**
+ * Tests an error condition when the {@code @WorkDirectory} annotation is
placed on multiple elements.
+ */
+ @Test
+ void testDuplicateFieldAndParameterInjection() {
+ execute(ErrorParameterResolutionTest.class)
+ .testEvents()
+ .assertThatEvents()
+ .filteredOn(type(EventType.FINISHED))
+ .isNotEmpty()
+ .are(finishedWithFailure(
+ instanceOf(ParameterResolutionException.class),
+ message(m -> m.contains("there exists a field annotated with
@WorkDirectory"))
+ ));
+ }
+
+ /**
+ * Test class for the {@link #testDuplicateFieldInjection()} test.
+ */
+ @ExtendWith(WorkDirectoryExtension.class)
+ static class ErrorFieldInjectionTest {
+ /** */
+ @WorkDirectory
+ private static Path workDir1;
+
+ /** */
+ @WorkDirectory
+ private Path workDir2;
+
+ /** */
+ @Test
+ public void test() {
+ fail("Should not reach here");
+ }
+ }
+
+ /**
+ * Tests an error condition when the {@code @WorkDirectory} annotation is
placed on multiple fields.
+ */
+ @Test
+ void testDuplicateFieldInjection() {
+ execute(ErrorFieldInjectionTest.class)
+ .allEvents()
+ .assertThatEvents()
+ .filteredOn(finishedWithFailure())
+ .isNotEmpty()
+ .are(finishedWithFailure(
+ instanceOf(IllegalStateException.class),
+ message(m -> m.contains("Test class must have a single field
of type"))
+ ));
+ }
+
+ /**
+ * Test class for the {@link #testSystemProperty()} test.
+ */
+ @ExtendWith(SystemPropertiesExtension.class)
+ @ExtendWith(WorkDirectoryExtension.class)
+ static class SystemPropertiesTest {
+ /** */
+ private static Path file1;
+
+ /** */
+ private static Path file2;
+
+ /** */
+ @AfterAll
+ static void verify() throws IOException {
+ assertTrue(Files.exists(file1));
+ assertFalse(Files.exists(file2));
+
+ Files.delete(file1);
+ }
+
+ /** */
+ @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
+ @WithSystemProperty(key =
WorkDirectoryExtension.KEEP_WORK_DIR_PROPERTY, value = "true")
+ @Test
+ void test1(@WorkDirectory Path workDir) throws IOException {
+ file1 = Files.createFile(workDir.resolve("foo"));
+ }
+
+ /** */
+ @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
+ @Test
+ void test2(@WorkDirectory Path workDir) throws IOException {
+ file2 = Files.createFile(workDir.resolve("foo"));
+ }
+ }
+
+ /**
+ * Tests that a work directory can be preserved when a special system
property is set.
+ */
+ @Test
+ void testSystemProperty() {
+ assertExecutesSuccessfully(SystemPropertiesTest.class);
+ }
+
+ /**
+ * Executes the given test class on the test engine.
+ */
+ private static EngineExecutionResults execute(Class<?> testClass) {
+ return EngineTestKit.engine("junit-jupiter")
+ .selectors(selectClass(testClass))
+ .execute();
+ }
+
+ /**
+ * Executes the given test class and checks that it has run all its tests
successfully.
+ */
+ private static void assertExecutesSuccessfully(Class<?> testClass) {
+ execute(testClass)
+ .allEvents()
+ .assertThatEvents()
+ .filteredOn(type(EventType.FINISHED))
+ .isNotEmpty()
+ .are(finishedSuccessfully());
+ }
+}
diff --git a/parent/pom.xml b/parent/pom.xml
index 1719dc9..c77ce62 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -58,7 +58,7 @@
<javax.annotation.api.version>1.3.2</javax.annotation.api.version>
<jetbrains.annotations.version>20.1.0</jetbrains.annotations.version>
<jmh.framework.version>1.13</jmh.framework.version>
- <junit.jupiter.version>5.7.0</junit.jupiter.version>
+ <junit.version>5.8.1</junit.version>
<micronaut.version>2.1.2</micronaut.version>
<micronaut.test.junit5.version>2.3.1</micronaut.test.junit5.version>
<mockito.framework.version>3.8.0</mockito.framework.version>
@@ -485,21 +485,11 @@
</dependency>
<dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-engine</artifactId>
- <version>${junit.jupiter.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-api</artifactId>
- <version>${junit.jupiter.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-params</artifactId>
- <version>${junit.jupiter.version}</version>
+ <groupId>org.junit</groupId>
+ <artifactId>junit-bom</artifactId>
+ <version>${junit.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
</dependency>
<dependency>
@@ -1012,6 +1002,8 @@
<argLine>-Djava.util.logging.config.file=../../config/java.util.logging.properties</argLine>
<excludes>
<exclude>**/IT*.java</exclude>
+ <!-- Exclude inner classes (preserve default
behaviour) -->
+ <exclude>**/*$*</exclude>
</excludes>
</configuration>
</plugin>