Browse Source

Introduce Spring property to disable context pausing for tests

Spring Framework 7.0 introduced support for pausing inactive
application contexts between test classes and restarting them once they
are needed again. If pausing and restarting are fast, this feature does
not have a negative impact on test suites.

However, if the pausing or restarting of certain Lifecycle components
in the application context is slow, that can have a negative impact on
the duration of the overall test suite.

In gh-36044, we hope to find a way to avoid unnecessarily pausing an
application context after a test class if the same context is used by
the next test class that is run. That should help reduce the risk of a
negative impact caused by the pause/restart feature; however, for
certain scenarios that may not be enough. In light of that, this commit
introduces a mechanism for completely disabling the pausing feature via
a Spring property or JVM system property, as follows.

-Dspring.test.context.cache.pause=never

See gh-35168
See gh-36044
Closes gh-36117
pull/36132/head
Sam Brannen 3 weeks ago
parent
commit
9711db787e
  1. 4
      framework-docs/modules/ROOT/pages/appendix.adoc
  2. 16
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/caching.adoc
  3. 1
      spring-core/src/main/java/org/springframework/core/SpringProperties.java
  4. 74
      spring-test/src/main/java/org/springframework/test/context/cache/ContextCache.java
  5. 24
      spring-test/src/main/java/org/springframework/test/context/cache/ContextCacheUtils.java
  6. 36
      spring-test/src/main/java/org/springframework/test/context/cache/DefaultContextCache.java
  7. 201
      spring-test/src/test/java/org/springframework/test/context/cache/ContextCachePauseModeTests.java
  8. 2
      spring-test/src/test/java/org/springframework/test/context/cache/ContextCacheTests.java
  9. 174
      spring-test/src/test/java/org/springframework/test/context/cache/ContextCacheUtilsTests.java

4
framework-docs/modules/ROOT/pages/appendix.adoc

@ -124,6 +124,10 @@ on a test class. See xref:testing/annotations/integration-junit-jupiter.adoc#int @@ -124,6 +124,10 @@ on a test class. See xref:testing/annotations/integration-junit-jupiter.adoc#int
| The maximum size of the context cache in the _Spring TestContext Framework_. See
xref:testing/testcontext-framework/ctx-management/caching.adoc[Context Caching].
| `spring.test.context.cache.pause`
| The pause mode for the context cache in the _Spring TestContext Framework_. See
xref:testing/testcontext-framework/ctx-management/caching.adoc[Context Caching].
| `spring.test.context.failure.threshold`
| The failure threshold for errors encountered while attempting to load an `ApplicationContext`
in the _Spring TestContext Framework_. See

16
framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/caching.adoc

@ -73,6 +73,22 @@ will be in a "stopped" state until the context is used again by a test. Note, ho @@ -73,6 +73,22 @@ will be in a "stopped" state until the context is used again by a test. Note, ho
that `SmartLifecycle` components can opt out of pausing by returning `false` from
`SmartLifecycle#isPauseable()`.
[TIP]
====
If you encounter issues with `Lifecycle` components that cannot or should not opt out of
pausing, or if you discover that your test suite runs more slowly due to the pausing and
restarting of application contexts, you can disable the pausing feature from the command
line or a build script by setting a JVM system property named
`spring.test.context.cache.pause` to `never`. For example:
```shell
-Dspring.test.context.cache.pause=never
```
As an alternative, you can set the same property via the
xref:appendix.adoc#appendix-spring-properties[`SpringProperties`] mechanism.
====
Since having a large number of application contexts loaded within a given test suite can
cause the suite to take an unnecessarily long time to run, it is often beneficial to
know exactly how many contexts have been loaded and cached. To view the statistics for

1
spring-core/src/main/java/org/springframework/core/SpringProperties.java

@ -50,6 +50,7 @@ import org.jspecify.annotations.Nullable; @@ -50,6 +50,7 @@ import org.jspecify.annotations.Nullable;
* @see org.springframework.test.context.NestedTestConfiguration#ENCLOSING_CONFIGURATION_PROPERTY_NAME
* @see org.springframework.test.context.TestConstructor#TEST_CONSTRUCTOR_AUTOWIRE_MODE_PROPERTY_NAME
* @see org.springframework.test.context.cache.ContextCache#MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME
* @see org.springframework.test.context.cache.ContextCache#CONTEXT_CACHE_PAUSE_PROPERTY_NAME
*/
public final class SpringProperties {

74
spring-test/src/main/java/org/springframework/test/context/cache/ContextCache.java vendored

@ -16,6 +16,10 @@ @@ -16,6 +16,10 @@
package org.springframework.test.context.cache;
import java.util.Locale;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationContext;
@ -83,6 +87,24 @@ public interface ContextCache { @@ -83,6 +87,24 @@ public interface ContextCache {
*/
String MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME = "spring.test.context.cache.maxSize";
/**
* System property used to configure whether inactive application contexts
* stored in the {@link ContextCache} should be paused: {@value}.
* <p>Defaults to {@code always}. Set this property to {@code never} to
* disable pausing of inactive application contexts &mdash; for example:
* <p>{@code -Dspring.test.context.cache.pause=never}
* <p>May alternatively be configured via the
* {@link org.springframework.core.SpringProperties} mechanism.
* <p>Note that implementations of {@code ContextCache} are not required to
* support context pausing. Consult the documentation of the corresponding
* implementation for details.
* @since 7.0.3
* @see PauseMode
* @see org.springframework.context.ConfigurableApplicationContext#pause()
* @see #unregisterContextUsage(MergedContextConfiguration, Class)
*/
String CONTEXT_CACHE_PAUSE_PROPERTY_NAME = "spring.test.context.cache.pause";
/**
* Determine whether there is a cached context for the given key.
@ -221,7 +243,8 @@ public interface ContextCache { @@ -221,7 +243,8 @@ public interface ContextCache {
* {@link MergedContextConfiguration} and any of its parents.
* <p>If no other test classes are actively using the same application
* context(s), the application context(s) should be
* {@linkplain org.springframework.context.ConfigurableApplicationContext#pause() paused}.
* {@linkplain org.springframework.context.ConfigurableApplicationContext#pause()
* paused} according to the configured {@link PauseMode}.
* <p>The default implementation of this method does nothing. Concrete
* implementations are therefore highly encouraged to override this
* method, {@link #registerContextUsage(MergedContextConfiguration, Class)},
@ -336,4 +359,53 @@ public interface ContextCache { @@ -336,4 +359,53 @@ public interface ContextCache {
}
/**
* Enumeration of <em>modes</em> that dictate whether inactive application contexts
* stored in the {@link ContextCache} should be
* {@linkplain org.springframework.context.ConfigurableApplicationContext#pause() paused}.
*
* @since 7.0.3
* @see #ALWAYS
* @see #NEVER
* @see ContextCache#CONTEXT_CACHE_PAUSE_PROPERTY_NAME
*/
enum PauseMode {
/**
* Always pause inactive application contexts.
*/
ALWAYS,
/**
* Never pause inactive application contexts, effectively disabling the
* pausing feature of the {@link ContextCache}.
*/
NEVER;
/**
* Get the {@code PauseMode} enum constant with the supplied name,
* {@linkplain String#strip() stripped} and ignoring case.
* @param name the name of the enum constant to retrieve
* @return the corresponding enum constant or {@code null} if not found
* @see PauseMode#valueOf(String)
*/
public static @Nullable PauseMode from(@Nullable String name) {
if (name == null) {
return null;
}
try {
return PauseMode.valueOf(name.strip().toUpperCase(Locale.ROOT));
}
catch (IllegalArgumentException ex) {
Log logger = LogFactory.getLog(PauseMode.class);
if (logger.isDebugEnabled()) {
logger.debug("Failed to parse PauseMode from '%s': %s"
.formatted(name, ex.getMessage()));
}
return null;
}
}
}
}

24
spring-test/src/main/java/org/springframework/test/context/cache/ContextCacheUtils.java vendored

@ -18,6 +18,7 @@ package org.springframework.test.context.cache; @@ -18,6 +18,7 @@ package org.springframework.test.context.cache;
import org.springframework.core.SpringProperties;
import org.springframework.test.context.CacheAwareContextLoaderDelegate;
import org.springframework.test.context.cache.ContextCache.PauseMode;
import org.springframework.util.StringUtils;
/**
@ -60,6 +61,29 @@ public abstract class ContextCacheUtils { @@ -60,6 +61,29 @@ public abstract class ContextCacheUtils {
return retrieveProperty(propertyName, defaultValue);
}
/**
* Retrieve the {@link PauseMode} for the {@link ContextCache}.
* <p>Uses {@link SpringProperties} to retrieve a system property or Spring
* property named {@value ContextCache#CONTEXT_CACHE_PAUSE_PROPERTY_NAME}.
* <p>Defaults to {@link PauseMode#ALWAYS} if no such property has been set.
* @return the configured or default {@code PauseMode}
* @since 7.0.3
* @see ContextCache#CONTEXT_CACHE_PAUSE_PROPERTY_NAME
* @see PauseMode#from(String)
*/
public static PauseMode retrievePauseMode() {
String value = SpringProperties.getProperty(ContextCache.CONTEXT_CACHE_PAUSE_PROPERTY_NAME);
if (StringUtils.hasText(value)) {
PauseMode pauseMode = PauseMode.from(value);
if (pauseMode == null) {
throw new IllegalArgumentException("Unsupported value '%s' for property '%s'"
.formatted(value, ContextCache.CONTEXT_CACHE_PAUSE_PROPERTY_NAME));
}
return pauseMode;
}
return PauseMode.ALWAYS;
}
private static int retrieveProperty(String key, int defaultValue) {
try {
String value = SpringProperties.getProperty(key);

36
spring-test/src/main/java/org/springframework/test/context/cache/DefaultContextCache.java vendored

@ -49,10 +49,15 @@ import org.springframework.util.Assert; @@ -49,10 +49,15 @@ import org.springframework.util.Assert;
* constructor argument} or set via a system property or Spring property named
* {@value ContextCache#MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME}.
*
* <p>The {@link PauseMode} may be supplied as a {@linkplain #DefaultContextCache(int, PauseMode)
* constructor argument} or set via a system property or Spring property named
* {@value ContextCache#CONTEXT_CACHE_PAUSE_PROPERTY_NAME}.
*
* @author Sam Brannen
* @author Juergen Hoeller
* @since 2.5
* @see ContextCacheUtils#retrieveMaxCacheSize()
* @see ContextCacheUtils#retrievePauseMode()
*/
public class DefaultContextCache implements ContextCache {
@ -91,6 +96,8 @@ public class DefaultContextCache implements ContextCache { @@ -91,6 +96,8 @@ public class DefaultContextCache implements ContextCache {
private final int maxSize;
private final PauseMode pauseMode;
private final AtomicInteger hitCount = new AtomicInteger();
private final AtomicInteger missCount = new AtomicInteger();
@ -98,10 +105,13 @@ public class DefaultContextCache implements ContextCache { @@ -98,10 +105,13 @@ public class DefaultContextCache implements ContextCache {
/**
* Create a new {@code DefaultContextCache} using the maximum cache size
* obtained via {@link ContextCacheUtils#retrieveMaxCacheSize()}.
* obtained via {@link ContextCacheUtils#retrieveMaxCacheSize()} and the
* {@link PauseMode} obtained via {@link ContextCacheUtils#retrievePauseMode()}.
* @since 4.3
* @see #DefaultContextCache(int)
* @see #DefaultContextCache(int, PauseMode)
* @see ContextCacheUtils#retrieveMaxCacheSize()
* @see ContextCacheUtils#retrievePauseMode()
*/
public DefaultContextCache() {
this(ContextCacheUtils.retrieveMaxCacheSize());
@ -109,16 +119,35 @@ public class DefaultContextCache implements ContextCache { @@ -109,16 +119,35 @@ public class DefaultContextCache implements ContextCache {
/**
* Create a new {@code DefaultContextCache} using the supplied maximum
* cache size.
* cache size and the {@link PauseMode} obtained via
* {@link ContextCacheUtils#retrievePauseMode()}.
* @param maxSize the maximum cache size
* @throws IllegalArgumentException if the supplied {@code maxSize} value
* is not positive
* @since 4.3
* @see #DefaultContextCache()
* @see #DefaultContextCache(int, PauseMode)
* @see ContextCacheUtils#retrievePauseMode()
*/
public DefaultContextCache(int maxSize) {
this(maxSize, ContextCacheUtils.retrievePauseMode());
}
/**
* Create a new {@code DefaultContextCache} using the supplied maximum
* cache size and {@link PauseMode}.
* @param maxSize the maximum cache size
* @param pauseMode the {@code PauseMode} to use
* @throws IllegalArgumentException if the supplied {@code maxSize} value
* is not positive or if the supplied {@code PauseMode} is {@code null}
* @since 7.0.3
* @see #DefaultContextCache()
*/
public DefaultContextCache(int maxSize, PauseMode pauseMode) {
Assert.isTrue(maxSize > 0, "'maxSize' must be positive");
Assert.notNull(pauseMode, "'pauseMode' must not be null");
this.maxSize = maxSize;
this.pauseMode = pauseMode;
}
@ -222,7 +251,8 @@ public class DefaultContextCache implements ContextCache { @@ -222,7 +251,8 @@ public class DefaultContextCache implements ContextCache {
Set<Class<?>> activeTestClasses = getActiveTestClasses(mergedConfig);
activeTestClasses.remove(testClass);
if (activeTestClasses.isEmpty()) {
if (context instanceof ConfigurableApplicationContext cac && cac.isRunning()) {
if ((this.pauseMode == PauseMode.ALWAYS) &&
(context instanceof ConfigurableApplicationContext cac && cac.isRunning())) {
cac.pause();
}
this.contextUsageMap.remove(mergedConfig);

201
spring-test/src/test/java/org/springframework/test/context/cache/ContextCachePauseModeTests.java vendored

@ -0,0 +1,201 @@ @@ -0,0 +1,201 @@
/*
* Copyright 2002-present the original author or authors.
*
* Licensed 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
*
* https://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.springframework.test.context.cache;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextCustomizerFactories;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestContextTestUtils;
import org.springframework.test.context.cache.ContextCache.PauseMode;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.cache.ContextCache.DEFAULT_MAX_CONTEXT_CACHE_SIZE;
import static org.springframework.test.context.cache.ContextCacheTestUtils.assertContextCacheStatistics;
/**
* Integration tests for verifying proper behavior of the {@link ContextCache} in
* conjunction with {@link PauseMode}.
*
* @author Sam Brannen
* @since 7.0.3
* @see ContextCacheTests
* @see UnusedContextsIntegrationTests
*/
class ContextCachePauseModeTests {
private ContextCache contextCache;
@BeforeEach
@AfterEach
void clearApplicationEvents() {
EventTracker.events.clear();
}
@Test
void topLevelTestClassesWithPauseModeAlways() {
this.contextCache = new DefaultContextCache(DEFAULT_MAX_CONTEXT_CACHE_SIZE, PauseMode.ALWAYS);
loadCtxAndAssertStats(TestCase1A.class, 1, 1, 0, 1);
assertThat(EventTracker.events).containsExactly("ContextRefreshed:TestCase1A", "ContextPaused:TestCase1A");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1A.class, 1, 1, 1, 1);
assertThat(EventTracker.events).containsExactly("ContextRestarted:TestCase1A", "ContextPaused:TestCase1A");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1B.class, 1, 1, 2, 1);
assertThat(EventTracker.events).containsExactly("ContextRestarted:TestCase1A", "ContextPaused:TestCase1A");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1A.class, 1, 1, 3, 1);
assertThat(EventTracker.events).containsExactly("ContextRestarted:TestCase1A", "ContextPaused:TestCase1A");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase2.class, 2, 1, 3, 2);
assertThat(EventTracker.events).containsExactly("ContextRefreshed:TestCase2", "ContextPaused:TestCase2");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1B.class, 2, 1, 4, 2);
assertThat(EventTracker.events).containsExactly("ContextRestarted:TestCase1A", "ContextPaused:TestCase1A");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1A.class, 2, 1, 5, 2);
assertThat(EventTracker.events).containsExactly("ContextRestarted:TestCase1A", "ContextPaused:TestCase1A");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase2.class, 2, 1, 6, 2);
assertThat(EventTracker.events).containsExactly("ContextRestarted:TestCase2", "ContextPaused:TestCase2");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase2.class, 2, 1, 7, 2);
assertThat(EventTracker.events).containsExactly("ContextRestarted:TestCase2", "ContextPaused:TestCase2");
clearApplicationEvents();
markContextDirty(TestCase2.class);
assertThat(EventTracker.events).containsExactly("ContextClosed:TestCase2");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase2.class, 2, 1, 7, 3);
assertThat(EventTracker.events).containsExactly("ContextRefreshed:TestCase2", "ContextPaused:TestCase2");
clearApplicationEvents();
}
@Test
void topLevelTestClassesWithPauseModeNever() {
this.contextCache = new DefaultContextCache(DEFAULT_MAX_CONTEXT_CACHE_SIZE, PauseMode.NEVER);
loadCtxAndAssertStats(TestCase1A.class, 1, 1, 0, 1);
assertThat(EventTracker.events).containsExactly("ContextRefreshed:TestCase1A");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1A.class, 1, 1, 1, 1);
assertThat(EventTracker.events).isEmpty();
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1B.class, 1, 1, 2, 1);
assertThat(EventTracker.events).isEmpty();
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1A.class, 1, 1, 3, 1);
assertThat(EventTracker.events).isEmpty();
clearApplicationEvents();
loadCtxAndAssertStats(TestCase2.class, 2, 1, 3, 2);
assertThat(EventTracker.events).containsExactly("ContextRefreshed:TestCase2");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1B.class, 2, 1, 4, 2);
assertThat(EventTracker.events).isEmpty();
clearApplicationEvents();
loadCtxAndAssertStats(TestCase1A.class, 2, 1, 5, 2);
assertThat(EventTracker.events).isEmpty();
clearApplicationEvents();
loadCtxAndAssertStats(TestCase2.class, 2, 1, 6, 2);
assertThat(EventTracker.events).isEmpty();
clearApplicationEvents();
loadCtxAndAssertStats(TestCase2.class, 2, 1, 7, 2);
assertThat(EventTracker.events).isEmpty();
clearApplicationEvents();
markContextDirty(TestCase2.class);
assertThat(EventTracker.events).containsExactly("ContextClosed:TestCase2");
clearApplicationEvents();
loadCtxAndAssertStats(TestCase2.class, 2, 1, 7, 3);
assertThat(EventTracker.events).containsExactly("ContextRefreshed:TestCase2");
clearApplicationEvents();
}
private void loadCtxAndAssertStats(Class<?> testClass, int expectedSize, int expectedActiveContextsCount,
int expectedHitCount, int expectedMissCount) {
TestContext testContext = TestContextTestUtils.buildTestContext(testClass, contextCache);
ApplicationContext context = testContext.getApplicationContext();
assertThat(context).isNotNull();
assertContextCacheStatistics(contextCache, testClass.getName(), expectedSize, expectedActiveContextsCount,
expectedHitCount, expectedMissCount);
testContext.markApplicationContextUnused();
assertThat(contextCache.getContextUsageCount())
.as("active contexts in cache (%s)", testClass.getSimpleName()).isZero();
}
private void markContextDirty(Class<?> testClass) {
TestContext testContext = TestContextTestUtils.buildTestContext(testClass, contextCache);
testContext.markApplicationContextDirty(HierarchyMode.EXHAUSTIVE);
}
@Configuration
@Import(EventTracker.class)
static class Config1 {
}
@Configuration
@Import(EventTracker.class)
static class Config2 {
}
@ContextConfiguration(classes = Config1.class)
@ContextCustomizerFactories(DisplayNameCustomizerFactory.class)
private abstract static class AbstractTestCase1 {
}
private static class TestCase1A extends AbstractTestCase1 {
}
private static class TestCase1B extends AbstractTestCase1 {
}
@ContextConfiguration(classes = Config2.class)
@ContextCustomizerFactories(DisplayNameCustomizerFactory.class)
private static class TestCase2 {
}
}

2
spring-test/src/test/java/org/springframework/test/context/cache/ContextCacheTests.java vendored

@ -71,6 +71,8 @@ class ContextCacheTests { @@ -71,6 +71,8 @@ class ContextCacheTests {
assertContextCacheStatistics(contextCache, testClass.getName(), expectedSize, expectedActiveContextsCount,
expectedHitCount, expectedMissCount);
testContext.markApplicationContextUnused();
assertThat(contextCache.getContextUsageCount())
.as("active contexts in cache (%s)", testClass.getSimpleName()).isZero();
}

174
spring-test/src/test/java/org/springframework/test/context/cache/ContextCacheUtilsTests.java vendored

@ -18,14 +18,21 @@ package org.springframework.test.context.cache; @@ -18,14 +18,21 @@ package org.springframework.test.context.cache;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.FieldSource;
import org.springframework.core.SpringProperties;
import org.springframework.test.context.cache.ContextCache.PauseMode;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.springframework.test.context.cache.ContextCache.CONTEXT_CACHE_PAUSE_PROPERTY_NAME;
import static org.springframework.test.context.cache.ContextCache.DEFAULT_MAX_CONTEXT_CACHE_SIZE;
import static org.springframework.test.context.cache.ContextCache.MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME;
import static org.springframework.test.context.cache.ContextCacheUtils.retrieveMaxCacheSize;
import static org.springframework.test.context.cache.ContextCacheUtils.retrievePauseMode;
/**
* Tests for {@link ContextCacheUtils}.
@ -35,56 +42,141 @@ import static org.springframework.test.context.cache.ContextCacheUtils.retrieveM @@ -35,56 +42,141 @@ import static org.springframework.test.context.cache.ContextCacheUtils.retrieveM
*/
class ContextCacheUtilsTests {
@BeforeEach
@AfterEach
void clearProperties() {
System.clearProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME);
SpringProperties.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, null);
}
@Nested
class MaxCacheSizeTests {
@Test
void retrieveMaxCacheSizeFromDefault() {
assertDefaultValue();
}
@BeforeEach
@AfterEach
void clearProperties() {
System.clearProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME);
SpringProperties.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, null);
}
@Test
void retrieveMaxCacheSizeFromBogusSystemProperty() {
System.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "bogus");
assertDefaultValue();
}
@Test
void retrieveMaxCacheSizeFromDefault() {
assertDefaultValue();
}
@Test
void retrieveMaxCacheSizeFromBogusSpringProperty() {
SpringProperties.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "bogus");
assertDefaultValue();
}
@Test
void retrieveMaxCacheSizeFromBogusSystemProperty() {
System.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "bogus");
assertDefaultValue();
}
@Test
void retrieveMaxCacheSizeFromDecimalSpringProperty() {
SpringProperties.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "3.14");
assertDefaultValue();
}
@Test
void retrieveMaxCacheSizeFromBogusSpringProperty() {
SpringProperties.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "bogus");
assertDefaultValue();
}
@Test
void retrieveMaxCacheSizeFromSystemProperty() {
System.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "42");
assertThat(retrieveMaxCacheSize()).isEqualTo(42);
}
@Test
void retrieveMaxCacheSizeFromDecimalSpringProperty() {
SpringProperties.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "3.14");
assertDefaultValue();
}
@Test
void retrieveMaxCacheSizeFromSystemPropertyContainingWhitespace() {
System.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "42\t");
assertThat(retrieveMaxCacheSize()).isEqualTo(42);
}
@Test
void retrieveMaxCacheSizeFromSystemProperty() {
System.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "42");
assertThat(retrieveMaxCacheSize()).isEqualTo(42);
}
@Test
void retrieveMaxCacheSizeFromSystemPropertyContainingWhitespace() {
System.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "42\t");
assertThat(retrieveMaxCacheSize()).isEqualTo(42);
}
@Test
void retrieveMaxCacheSizeFromSpringProperty() {
SpringProperties.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "99");
assertThat(retrieveMaxCacheSize()).isEqualTo(99);
}
@Test
void retrieveMaxCacheSizeFromSpringProperty() {
SpringProperties.setProperty(MAX_CONTEXT_CACHE_SIZE_PROPERTY_NAME, "99");
assertThat(retrieveMaxCacheSize()).isEqualTo(99);
private static void assertDefaultValue() {
assertThat(retrieveMaxCacheSize()).isEqualTo(DEFAULT_MAX_CONTEXT_CACHE_SIZE);
}
}
private static void assertDefaultValue() {
assertThat(retrieveMaxCacheSize()).isEqualTo(DEFAULT_MAX_CONTEXT_CACHE_SIZE);
/**
* Tests for {@link PauseMode} support.
* @since 7.0.3
*/
@Nested
class PauseModeTests {
static final String[] ALWAYS_VALUES = {
"always",
"Always",
"ALWAYS",
"\talways\u000B"
};
static final String[] NEVER_VALUES = {
"never",
"Never",
"NEVER",
"\tnever\u000B"
};
@BeforeEach
@AfterEach
void clearProperties() {
System.clearProperty(CONTEXT_CACHE_PAUSE_PROPERTY_NAME);
SpringProperties.setProperty(CONTEXT_CACHE_PAUSE_PROPERTY_NAME, null);
}
@Test
void retrievePauseModeFromDefault() {
assertThat(retrievePauseMode()).isEqualTo(PauseMode.ALWAYS);
}
@Test
void retrievePauseModeFromBogusSystemProperty() {
System.setProperty(CONTEXT_CACHE_PAUSE_PROPERTY_NAME, "bogus");
asssertUnsupportedValue();
}
@Test
void retrievePauseModeFromBogusSpringProperty() {
SpringProperties.setProperty(CONTEXT_CACHE_PAUSE_PROPERTY_NAME, "bogus");
asssertUnsupportedValue();
}
@ParameterizedTest
@FieldSource("ALWAYS_VALUES")
void retrievePauseModeFromSystemPropertyWithValueAlways(String value) {
System.setProperty(CONTEXT_CACHE_PAUSE_PROPERTY_NAME, value);
assertThat(retrievePauseMode()).isEqualTo(PauseMode.ALWAYS);
}
@ParameterizedTest
@FieldSource("NEVER_VALUES")
void retrievePauseModeFromSystemPropertyWithValueNever(String value) {
System.setProperty(CONTEXT_CACHE_PAUSE_PROPERTY_NAME, value);
assertThat(retrievePauseMode()).isEqualTo(PauseMode.NEVER);
}
@ParameterizedTest
@FieldSource("ALWAYS_VALUES")
void retrievePauseModeFromSpringPropertyWithValueAlways(String value) {
SpringProperties.setProperty(CONTEXT_CACHE_PAUSE_PROPERTY_NAME, value);
assertThat(retrievePauseMode()).isEqualTo(PauseMode.ALWAYS);
}
@ParameterizedTest
@FieldSource("NEVER_VALUES")
void retrievePauseModeFromSpringPropertyWithValueNever(String value) {
SpringProperties.setProperty(CONTEXT_CACHE_PAUSE_PROPERTY_NAME, value);
assertThat(retrievePauseMode()).isEqualTo(PauseMode.NEVER);
}
private void asssertUnsupportedValue() {
assertThatIllegalArgumentException()
.isThrownBy(ContextCacheUtils::retrievePauseMode)
.withMessage("Unsupported value 'bogus' for property 'spring.test.context.cache.pause'");
}
}
}

Loading…
Cancel
Save