From b33dbc4ea738c4a9fd244dccfe12689a9899121e Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 24 Sep 2019 12:17:47 -0700 Subject: [PATCH 01/10] Added timeout config parameter --- .../org/junit/jupiter/engine/Constants.java | 20 +++++++++++ .../engine/config/JupiterConfiguration.java | 1 + .../engine/extension/TimeoutExtension.java | 28 ++++++++++++++- .../org.junit.jupiter.engine/module-info.java | 1 + .../extension/TimeoutExtensionTests.java | 34 +++++++++---------- 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java index f8af3be62f9c..de0b50485ea1 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java @@ -425,6 +425,26 @@ public final class Constants { @API(status = EXPERIMENTAL, since = "5.5") public static final String DEFAULT_AFTER_ALL_METHOD_TIMEOUT_PROPERTY_NAME = JupiterConfiguration.DEFAULT_AFTER_ALL_METHOD_TIMEOUT_PROPERTY_NAME; + /** + * Property used to determine if timeouts are applied to tests: {@value}. + * + *

The value of this property will be used to toggle whether + * {@link org.junit.jupiter.api.Timeout @Timeout} is applied to tests.

+ * + *

Examples

+ * + * + * + * @see org.junit.jupiter.api.extension.ExecutionCondition + * @since 5.6 + */ + @API(status = EXPERIMENTAL, since = "5.6") + public static final String TIMEOUT_MODE_PROPERTY_NAME = JupiterConfiguration.TIMEOUT_MODE_PROPERTY_NAME; + private Constants() { /* no-op */ } diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java index 67b31bebbcf4..c9a14c5bcb25 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/config/JupiterConfiguration.java @@ -46,6 +46,7 @@ public interface JupiterConfiguration { String DEFAULT_BEFORE_EACH_METHOD_TIMEOUT_PROPERTY_NAME = "junit.jupiter.execution.timeout.beforeeach.method.default"; String DEFAULT_AFTER_EACH_METHOD_TIMEOUT_PROPERTY_NAME = "junit.jupiter.execution.timeout.aftereach.method.default"; String DEFAULT_AFTER_ALL_METHOD_TIMEOUT_PROPERTY_NAME = "junit.jupiter.execution.timeout.afterall.method.default"; + String TIMEOUT_MODE_PROPERTY_NAME = "junit.jupiter.execution.timeout.mode"; Optional getRawConfigurationParameter(String key); diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java index b75b5b044904..ef6d62db4d9c 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java @@ -10,6 +10,9 @@ package org.junit.jupiter.engine.extension; +import static org.junit.jupiter.engine.config.JupiterConfiguration.TIMEOUT_MODE_PROPERTY_NAME; + +import java.lang.management.ManagementFactory; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; import java.util.Optional; @@ -38,6 +41,8 @@ class TimeoutExtension implements BeforeAllCallback, BeforeEachCallback, Invocat private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(Timeout.class); private static final String TESTABLE_METHOD_TIMEOUT_KEY = "testable_method_timeout_from_annotation"; private static final String GLOBAL_TIMEOUT_CONFIG_KEY = "global_timeout_config"; + public static final String DISABLED = "disabled"; + public static final String DISABLED_ON_DEBUG = "disabled_on_debug"; @Override public void beforeAll(ExtensionContext context) { @@ -50,6 +55,7 @@ public void beforeEach(ExtensionContext context) { } private void readAndStoreTimeoutSoChildrenInheritIt(ExtensionContext context) { + readTimeoutFromAnnotation(context.getElement()).ifPresent( timeout -> context.getStore(NAMESPACE).put(TESTABLE_METHOD_TIMEOUT_KEY, timeout)); } @@ -145,7 +151,7 @@ private TimeoutConfiguration getGlobalTimeoutConfiguration(ExtensionContext exte private Invocation decorate(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext, TimeoutDuration timeout) { - if (timeout == null) { + if (timeout == null || isDebuggingOrDisabled(extensionContext)) { return invocation; } return new TimeoutInvocation<>(invocation, timeout, getExecutor(extensionContext), @@ -165,6 +171,26 @@ private ScheduledExecutorService getExecutor(ExtensionContext extensionContext) return extensionContext.getRoot().getStore(NAMESPACE).getOrComputeIfAbsent(ExecutorResource.class).get(); } + private boolean isDebuggingOrDisabled(ExtensionContext extensionContext) { + if (extensionContext.getConfigurationParameter(TIMEOUT_MODE_PROPERTY_NAME).isPresent()) { + if (extensionContext.getConfigurationParameter(TIMEOUT_MODE_PROPERTY_NAME).get().equals(DISABLED)) { + return true; + } + else if (extensionContext.getConfigurationParameter(TIMEOUT_MODE_PROPERTY_NAME).get().equals( + DISABLED_ON_DEBUG)) { + for (final String argument : ManagementFactory.getRuntimeMXBean().getInputArguments()) { + if ("-Xdebug".equals(argument)) { + return true; + } + else if (argument.startsWith("-agentlib:jdwp")) { + return true; + } + } + } + } + return false; + } + @FunctionalInterface private interface TimeoutProvider extends Function> { } diff --git a/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java b/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java index 851c133e741c..58320468c0b5 100644 --- a/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java +++ b/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java @@ -14,6 +14,7 @@ requires transitive org.junit.jupiter.api; requires transitive org.junit.platform.engine; requires transitive org.opentest4j; + requires transitive java.management; // exports org.junit.jupiter.engine; // Constants... diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java index d85650564bb8..ae09a4f53094 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java @@ -16,13 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.DynamicTest.dynamicTest; -import static org.junit.jupiter.engine.Constants.DEFAULT_AFTER_ALL_METHOD_TIMEOUT_PROPERTY_NAME; -import static org.junit.jupiter.engine.Constants.DEFAULT_AFTER_EACH_METHOD_TIMEOUT_PROPERTY_NAME; -import static org.junit.jupiter.engine.Constants.DEFAULT_BEFORE_ALL_METHOD_TIMEOUT_PROPERTY_NAME; -import static org.junit.jupiter.engine.Constants.DEFAULT_BEFORE_EACH_METHOD_TIMEOUT_PROPERTY_NAME; -import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_FACTORY_METHOD_TIMEOUT_PROPERTY_NAME; -import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_METHOD_TIMEOUT_PROPERTY_NAME; -import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_TEMPLATE_METHOD_TIMEOUT_PROPERTY_NAME; +import static org.junit.jupiter.engine.Constants.*; import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; import static org.junit.platform.engine.TestExecutionResult.Status.FAILED; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; @@ -34,17 +28,7 @@ import java.util.concurrent.TimeoutException; import java.util.stream.Stream; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.RepeatedTest; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestFactory; -import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.*; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.testkit.engine.EngineExecutionResults; @@ -74,6 +58,19 @@ void appliesTimeoutOnAnnotatedTestMethods() { .hasMessage("testMethod() timed out after 10 milliseconds"); } + @Test + @DisplayName("is not applied on annotated @Test methods using timeout mode: disabled") + void doesNotApplyTimeoutOnAnnotatedTestMethodsUsingDisabledTimeoutMode() { + EngineExecutionResults results = executeTests(request() // + .selectors(selectMethod(TimeoutAnnotatedTestMethodTestCase.class, "testMethod")) // + .configurationParameter(DEFAULT_TEST_METHOD_TIMEOUT_PROPERTY_NAME, "42ns") // + .configurationParameter(TIMEOUT_MODE_PROPERTY_NAME, "disabled").build()); + + Execution execution = findExecution(results.testEvents(), "testMethod()"); + assertThat(execution.getTerminationInfo().getExecutionResult().getThrowable()) // + .isEmpty(); + } + @Test @DisplayName("is applied on annotated @TestTemplate methods") void appliesTimeoutOnAnnotatedTestTemplateMethods() { @@ -289,6 +286,7 @@ private Execution findExecution(Events events, String displayName) { } static class TimeoutAnnotatedTestMethodTestCase { + @Test @Timeout(value = 10, unit = MILLISECONDS) void testMethod() throws Exception { From 5fc99d7c267e661c0e72d997a1f6ae97686136bf Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 24 Sep 2019 12:50:29 -0700 Subject: [PATCH 02/10] Fixed checkstyle error --- .../jupiter/engine/extension/TimeoutExtensionTests.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java index ae09a4f53094..9305c33e4582 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java @@ -16,7 +16,14 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.DynamicTest.dynamicTest; -import static org.junit.jupiter.engine.Constants.*; +import static org.junit.jupiter.engine.Constants.DEFAULT_AFTER_ALL_METHOD_TIMEOUT_PROPERTY_NAME; +import static org.junit.jupiter.engine.Constants.DEFAULT_AFTER_EACH_METHOD_TIMEOUT_PROPERTY_NAME; +import static org.junit.jupiter.engine.Constants.DEFAULT_BEFORE_ALL_METHOD_TIMEOUT_PROPERTY_NAME; +import static org.junit.jupiter.engine.Constants.DEFAULT_BEFORE_EACH_METHOD_TIMEOUT_PROPERTY_NAME; +import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_FACTORY_METHOD_TIMEOUT_PROPERTY_NAME; +import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_METHOD_TIMEOUT_PROPERTY_NAME; +import static org.junit.jupiter.engine.Constants.DEFAULT_TEST_TEMPLATE_METHOD_TIMEOUT_PROPERTY_NAME; +import static org.junit.jupiter.engine.Constants.TIMEOUT_MODE_PROPERTY_NAME; import static org.junit.platform.commons.util.CollectionUtils.getOnlyElement; import static org.junit.platform.engine.TestExecutionResult.Status.FAILED; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; From 7b85300093a973d1cb9d95c82661b17ea6dd5198 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 24 Sep 2019 13:03:50 -0700 Subject: [PATCH 03/10] fixed requested changes --- .../jupiter/engine/extension/TimeoutExtension.java | 1 - .../engine/extension/TimeoutExtensionTests.java | 12 +++++++++++- .../junit-jupiter-engine.expected.txt | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java index ef6d62db4d9c..24319a2333e0 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java @@ -55,7 +55,6 @@ public void beforeEach(ExtensionContext context) { } private void readAndStoreTimeoutSoChildrenInheritIt(ExtensionContext context) { - readTimeoutFromAnnotation(context.getElement()).ifPresent( timeout -> context.getStore(NAMESPACE).put(TESTABLE_METHOD_TIMEOUT_KEY, timeout)); } diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java index 9305c33e4582..fe9e29c9bcf3 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java @@ -35,7 +35,17 @@ import java.util.concurrent.TimeoutException; import java.util.stream.Stream; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.Timeout; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.testkit.engine.EngineExecutionResults; diff --git a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt index 3fff2c131e4a..511a17a24e45 100644 --- a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt +++ b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt @@ -4,6 +4,7 @@ requires org.apiguardian.api transitive requires org.junit.jupiter.api transitive requires org.junit.platform.engine transitive requires org.opentest4j transitive +requires java.management transitive ; uses org.junit.jupiter.api.extension.Extension provides org.junit.platform.engine.TestEngine with org.junit.jupiter.engine.JupiterTestEngine qualified opens org.junit.jupiter.engine.extension to org.junit.platform.commons From 5162dd3f116117484af1119adbed9da91805b858 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 24 Sep 2019 13:23:03 -0700 Subject: [PATCH 04/10] Fixed JarDescribeModuleTests error --- .../jar-describe-module/junit-jupiter-engine.expected.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt index 511a17a24e45..ee7444bf4faf 100644 --- a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt +++ b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt @@ -4,7 +4,7 @@ requires org.apiguardian.api transitive requires org.junit.jupiter.api transitive requires org.junit.platform.engine transitive requires org.opentest4j transitive -requires java.management transitive ; +requires java.management transitive uses org.junit.jupiter.api.extension.Extension provides org.junit.platform.engine.TestEngine with org.junit.jupiter.engine.JupiterTestEngine qualified opens org.junit.jupiter.engine.extension to org.junit.platform.commons From 29852d8739d37c78a58a86484ff850bb29d84330 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 24 Sep 2019 15:27:50 -0700 Subject: [PATCH 05/10] Fixed build errors --- .../junit/jupiter/engine/extension/TimeoutExtensionTests.java | 1 - .../jar-describe-module/junit-jupiter-engine.expected.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java index fe9e29c9bcf3..2e269c58b07d 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java @@ -303,7 +303,6 @@ private Execution findExecution(Events events, String displayName) { } static class TimeoutAnnotatedTestMethodTestCase { - @Test @Timeout(value = 10, unit = MILLISECONDS) void testMethod() throws Exception { diff --git a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt index ee7444bf4faf..67e18011b0fc 100644 --- a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt +++ b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt @@ -1,10 +1,10 @@ org.junit.jupiter.engine@${jupiterVersion} jar:file:.+junit-jupiter-engine/build/libs/junit-jupiter-engine-${jupiterVersion}.jar/!module-info.class requires java.base mandated +requires java.management transitive requires org.apiguardian.api transitive requires org.junit.jupiter.api transitive requires org.junit.platform.engine transitive requires org.opentest4j transitive -requires java.management transitive uses org.junit.jupiter.api.extension.Extension provides org.junit.platform.engine.TestEngine with org.junit.jupiter.engine.JupiterTestEngine qualified opens org.junit.jupiter.engine.extension to org.junit.platform.commons From dec9f7113e0714e8e52806d563e7a127db6c2e6d Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 24 Sep 2019 22:26:40 -0700 Subject: [PATCH 06/10] Modified Timeout Constant --- .../src/main/java/org/junit/jupiter/engine/Constants.java | 1 - 1 file changed, 1 deletion(-) diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java index de0b50485ea1..19bece899ad0 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java @@ -439,7 +439,6 @@ public final class Constants { *
  • {@code disabled_on_debug}: disables timeouts while debugging. * * - * @see org.junit.jupiter.api.extension.ExecutionCondition * @since 5.6 */ @API(status = EXPERIMENTAL, since = "5.6") From 43a672ed0bb445a1db58c84527c6595eaba2832d Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 25 Sep 2019 09:25:19 -0700 Subject: [PATCH 07/10] Fixed requested changes --- .../src/module/org.junit.jupiter.engine/module-info.java | 2 +- .../jar-describe-module/junit-jupiter-engine.expected.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java b/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java index 58320468c0b5..2f0b57e5be0e 100644 --- a/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java +++ b/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java @@ -14,7 +14,7 @@ requires transitive org.junit.jupiter.api; requires transitive org.junit.platform.engine; requires transitive org.opentest4j; - requires transitive java.management; + requires java.management; // exports org.junit.jupiter.engine; // Constants... diff --git a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt index 67e18011b0fc..2797a60947ef 100644 --- a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt +++ b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt @@ -1,6 +1,6 @@ org.junit.jupiter.engine@${jupiterVersion} jar:file:.+junit-jupiter-engine/build/libs/junit-jupiter-engine-${jupiterVersion}.jar/!module-info.class requires java.base mandated -requires java.management transitive +requires java.management requires org.apiguardian.api transitive requires org.junit.jupiter.api transitive requires org.junit.platform.engine transitive From 1ba3bdac36781b4eeed76f45920bf8941ea3cc5e Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 1 Oct 2019 20:20:26 -0700 Subject: [PATCH 08/10] Requested Changes without Integration Test --- .../engine/extension/TimeoutExtension.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java index 24319a2333e0..45e705b7119b 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java @@ -29,6 +29,8 @@ import org.junit.jupiter.api.extension.InvocationInterceptor; import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.support.AnnotationSupport; import org.junit.platform.commons.util.ClassUtils; import org.junit.platform.commons.util.ReflectionUtils; @@ -38,6 +40,8 @@ */ class TimeoutExtension implements BeforeAllCallback, BeforeEachCallback, InvocationInterceptor { + private static final Logger logger = LoggerFactory.getLogger(TimeoutExtension.class); + private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(Timeout.class); private static final String TESTABLE_METHOD_TIMEOUT_KEY = "testable_method_timeout_from_annotation"; private static final String GLOBAL_TIMEOUT_CONFIG_KEY = "global_timeout_config"; @@ -177,14 +181,16 @@ private boolean isDebuggingOrDisabled(ExtensionContext extensionContext) { } else if (extensionContext.getConfigurationParameter(TIMEOUT_MODE_PROPERTY_NAME).get().equals( DISABLED_ON_DEBUG)) { - for (final String argument : ManagementFactory.getRuntimeMXBean().getInputArguments()) { - if ("-Xdebug".equals(argument)) { - return true; - } - else if (argument.startsWith("-agentlib:jdwp")) { - return true; + try { + for (final String argument : ManagementFactory.getRuntimeMXBean().getInputArguments()) { + if (argument.startsWith("-agentlib:jdwp")) { + return true; + } } } + catch (NoClassDefFoundError cause) { + logger.warn(cause, () -> "ManagementFactory not found"); + } } } return false; From ce1892cb02b3917d061c414f0b49f08cb6017a52 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Tue, 8 Oct 2019 11:32:45 +0200 Subject: [PATCH 09/10] Move runtime input arguments getter to dedicated utility class --- .../engine/extension/TimeoutExtension.java | 48 +++++------ .../org.junit.jupiter.engine/module-info.java | 1 - .../platform/commons/util/RuntimeUtils.java | 80 +++++++++++++++++++ .../module-info.java | 3 +- .../commons/util/RuntimeUtilsTests.java | 33 ++++++++ .../junit-jupiter-engine.expected.txt | 1 - .../junit-platform-commons.expected.txt | 1 + 7 files changed, 137 insertions(+), 30 deletions(-) create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/RuntimeUtils.java create mode 100644 platform-tests/src/test/java/org/junit/platform/commons/util/RuntimeUtilsTests.java diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java index 45e705b7119b..6b7e36abdb20 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TimeoutExtension.java @@ -12,7 +12,6 @@ import static org.junit.jupiter.engine.config.JupiterConfiguration.TIMEOUT_MODE_PROPERTY_NAME; -import java.lang.management.ManagementFactory; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; import java.util.Optional; @@ -24,29 +23,28 @@ import org.junit.jupiter.api.Timeout; import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionConfigurationException; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; import org.junit.jupiter.api.extension.InvocationInterceptor; import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.support.AnnotationSupport; import org.junit.platform.commons.util.ClassUtils; import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.util.RuntimeUtils; /** * @since 5.5 */ class TimeoutExtension implements BeforeAllCallback, BeforeEachCallback, InvocationInterceptor { - private static final Logger logger = LoggerFactory.getLogger(TimeoutExtension.class); - private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(Timeout.class); private static final String TESTABLE_METHOD_TIMEOUT_KEY = "testable_method_timeout_from_annotation"; private static final String GLOBAL_TIMEOUT_CONFIG_KEY = "global_timeout_config"; - public static final String DISABLED = "disabled"; - public static final String DISABLED_ON_DEBUG = "disabled_on_debug"; + public static final String ENABLED_MODE_VALUE = "enabled"; + public static final String DISABLED_MODE_VALUE = "disabled"; + public static final String DISABLED_ON_DEBUG_MODE_VALUE = "disabled_on_debug"; @Override public void beforeAll(ExtensionContext context) { @@ -154,7 +152,7 @@ private TimeoutConfiguration getGlobalTimeoutConfiguration(ExtensionContext exte private Invocation decorate(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext, TimeoutDuration timeout) { - if (timeout == null || isDebuggingOrDisabled(extensionContext)) { + if (timeout == null || isModeIndicatingDisabled(extensionContext)) { return invocation; } return new TimeoutInvocation<>(invocation, timeout, getExecutor(extensionContext), @@ -174,26 +172,22 @@ private ScheduledExecutorService getExecutor(ExtensionContext extensionContext) return extensionContext.getRoot().getStore(NAMESPACE).getOrComputeIfAbsent(ExecutorResource.class).get(); } - private boolean isDebuggingOrDisabled(ExtensionContext extensionContext) { - if (extensionContext.getConfigurationParameter(TIMEOUT_MODE_PROPERTY_NAME).isPresent()) { - if (extensionContext.getConfigurationParameter(TIMEOUT_MODE_PROPERTY_NAME).get().equals(DISABLED)) { - return true; - } - else if (extensionContext.getConfigurationParameter(TIMEOUT_MODE_PROPERTY_NAME).get().equals( - DISABLED_ON_DEBUG)) { - try { - for (final String argument : ManagementFactory.getRuntimeMXBean().getInputArguments()) { - if (argument.startsWith("-agentlib:jdwp")) { - return true; - } - } - } - catch (NoClassDefFoundError cause) { - logger.warn(cause, () -> "ManagementFactory not found"); - } - } + private boolean isModeIndicatingDisabled(ExtensionContext extensionContext) { + Optional mode = extensionContext.getConfigurationParameter(TIMEOUT_MODE_PROPERTY_NAME); + return mode.filter(this::isDisabled).isPresent(); + } + + private boolean isDisabled(String mode) { + if (mode.equals(ENABLED_MODE_VALUE)) { + return false; + } + if (mode.equals(DISABLED_MODE_VALUE)) { + return true; + } + if (mode.equals(DISABLED_ON_DEBUG_MODE_VALUE)) { + return RuntimeUtils.isDebug(); } - return false; + throw new ExtensionConfigurationException("Unsupported timeout extension mode: " + mode); } @FunctionalInterface diff --git a/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java b/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java index 2f0b57e5be0e..851c133e741c 100644 --- a/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java +++ b/junit-jupiter-engine/src/module/org.junit.jupiter.engine/module-info.java @@ -14,7 +14,6 @@ requires transitive org.junit.jupiter.api; requires transitive org.junit.platform.engine; requires transitive org.opentest4j; - requires java.management; // exports org.junit.jupiter.engine; // Constants... diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/RuntimeUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/RuntimeUtils.java new file mode 100644 index 000000000000..0fd9579c79aa --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/RuntimeUtils.java @@ -0,0 +1,80 @@ +/* + * Copyright 2015-2019 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.commons.util; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.util.List; +import java.util.Optional; + +import org.apiguardian.api.API; + +/** + * Collection of utilities for working with {@link Runtime}, + * {@link java.lang.management.RuntimeMXBean}, etc. + * + *

    DISCLAIMER

    + * + *

    These utilities are intended solely for usage within the JUnit framework + * itself. Any usage by external parties is not supported. + * Use at your own risk! + * + * @since 1.6 + */ +@API(status = INTERNAL, since = "1.6") +public final class RuntimeUtils { + + private RuntimeUtils() { + /* no-op */ + } + + /** + * Try to get the input arguments the VM was started with. + */ + public static Optional> getInputArguments() { + Optional> managementFactoryClass = ReflectionUtils.tryToLoadClass( + "java.lang.management.ManagementFactory").toOptional(); + if (!managementFactoryClass.isPresent()) { + return Optional.empty(); + } + // Can't use "java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments()" + // directly as module "java.management" might not be available and/or the current platform + // doesn't support the Java Management Extensions (JMX) API (like Android?). + // See https://github.com/junit-team/junit4/pull/1187 + try { + Object bean = managementFactoryClass.get().getMethod("getRuntimeMXBean").invoke(null); + Class mx = ReflectionUtils.tryToLoadClass("java.lang.management.RuntimeMXBean").get(); + @SuppressWarnings("unchecked") + List args = (List) mx.getMethod("getInputArguments").invoke(bean); + return Optional.of(args); + } + catch (Exception e) { + return Optional.empty(); + } + } + + /** + * Try to determine whether the VM was started in debug mode or not. + */ + public static boolean isDebug() { + Optional> optionalArguments = getInputArguments(); + if (!optionalArguments.isPresent()) { + return false; + } + for (String argument : optionalArguments.get()) { + if (argument.startsWith("-agentlib:jdwp")) { + return true; + } + } + return false; + } + +} diff --git a/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java b/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java index 39b82ecee720..6086a63e4aee 100644 --- a/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java +++ b/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java @@ -9,7 +9,8 @@ */ module org.junit.platform.commons { - requires java.logging; // TODO Is "requires transitive java.logging" needed here? + requires java.logging; + requires java.management; // needed by RuntimeUtils to determine input arguments requires transitive org.apiguardian.api; exports org.junit.platform.commons; diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/RuntimeUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/RuntimeUtilsTests.java new file mode 100644 index 000000000000..b30dde8d719e --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/RuntimeUtilsTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2015-2019 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.commons.util; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link RuntimeUtils}. + * + * @since 1.6 + */ +class RuntimeUtilsTests { + + @Test + void jmxIsAvailableAndInputArgumentsAreReturned() { + var optionalArguments = RuntimeUtils.getInputArguments(); + assertTrue(optionalArguments.isPresent(), "JMX not available or something else happened..."); + var arguments = optionalArguments.get(); + assertNotNull(arguments); + } + +} diff --git a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt index 2797a60947ef..3fff2c131e4a 100644 --- a/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt +++ b/platform-tooling-support-tests/projects/jar-describe-module/junit-jupiter-engine.expected.txt @@ -1,6 +1,5 @@ org.junit.jupiter.engine@${jupiterVersion} jar:file:.+junit-jupiter-engine/build/libs/junit-jupiter-engine-${jupiterVersion}.jar/!module-info.class requires java.base mandated -requires java.management requires org.apiguardian.api transitive requires org.junit.jupiter.api transitive requires org.junit.platform.engine transitive diff --git a/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt b/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt index 543a7ccb8090..e157f1dc7ebf 100644 --- a/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt +++ b/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt @@ -5,6 +5,7 @@ exports org.junit.platform.commons.function exports org.junit.platform.commons.support requires java.base mandated requires java.logging +requires java.management requires org.apiguardian.api transitive qualified exports org.junit.platform.commons.logging to org.junit.jupiter.api org.junit.jupiter.engine org.junit.jupiter.migrationsupport org.junit.jupiter.params org.junit.platform.console org.junit.platform.engine org.junit.platform.launcher org.junit.platform.reporting org.junit.platform.runner org.junit.platform.suite.api org.junit.platform.testkit org.junit.vintage.engine qualified exports org.junit.platform.commons.util to org.junit.jupiter.api org.junit.jupiter.engine org.junit.jupiter.migrationsupport org.junit.jupiter.params org.junit.platform.console org.junit.platform.engine org.junit.platform.launcher org.junit.platform.reporting org.junit.platform.runner org.junit.platform.suite.api org.junit.platform.testkit org.junit.vintage.engine \ No newline at end of file From 8eb8211baccca75564d3c38ef6065232ad13c108 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 8 Oct 2019 18:56:50 -0700 Subject: [PATCH 10/10] Created new test for Timeout config (1959) --- .../extension/TimeoutExtensionTests.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java index 2e269c58b07d..ceef9e8d8200 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutExtensionTests.java @@ -48,6 +48,7 @@ import org.junit.jupiter.api.Timeout; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.RuntimeUtils; import org.junit.platform.testkit.engine.EngineExecutionResults; import org.junit.platform.testkit.engine.Events; import org.junit.platform.testkit.engine.Execution; @@ -88,6 +89,33 @@ void doesNotApplyTimeoutOnAnnotatedTestMethodsUsingDisabledTimeoutMode() { .isEmpty(); } + @Test + @DisplayName("is not applied on annotated @Test methods using timeout mode: disabled") + void applyTimeoutOnAnnotatedTestMethodsUsingDisabledOnDebugTimeoutMode() { + EngineExecutionResults results = executeTests(request() // + .selectors(selectMethod(TimeoutAnnotatedTestMethodTestCase.class, "testMethod")) // + .configurationParameter(DEFAULT_TEST_METHOD_TIMEOUT_PROPERTY_NAME, "42ns") // + .configurationParameter(TIMEOUT_MODE_PROPERTY_NAME, "disabled_on_debug").build()); + + Execution execution = findExecution(results.testEvents(), "testMethod()"); + + assertThat(execution.getDuration()) // + .isGreaterThanOrEqualTo(Duration.ofMillis(10)) // + // The check to see if debugging is pushing the timer just above 1 second + .isLessThan(Duration.ofSeconds(2)); + + // Should we test if we're debugging? This test will fail if we are debugging. + if (RuntimeUtils.isDebug()) { + assertThat(execution.getTerminationInfo().getExecutionResult().getThrowable()) // + .isEmpty(); + } + else { + assertThat(execution.getTerminationInfo().getExecutionResult().getThrowable().orElseThrow()) // + .isInstanceOf(TimeoutException.class) // + .hasMessage("testMethod() timed out after 10 milliseconds"); + } + } + @Test @DisplayName("is applied on annotated @TestTemplate methods") void appliesTimeoutOnAnnotatedTestTemplateMethods() {