Not sure whether this qualifies as a bug (since it's really unexpected and hard to understand why it happens) or an improvement...

Observed behavior:

If I have two tests for a spring boot application that uses autoconfigured EhCache that run in the following order: 1. test without @DirtiesContext 2. test with @DirtiesContext

The second test fails with net.sf.ehcache.CacheException: Another unnamed CacheManager already exists in the same VM

Expected behavior:

The second test shouldn't fail, as it should reuse the cache from the previous one.

Additional Information

This is essentially a variant of https://jira.spring.io/browse/SPR-12687. The difference is that Spring Boot's EhCacheCacheConfiguration uses org.springframework.cache.ehcache.EhCacheManagerUtils, which always uses new CacheManager, leading to the described error.

Switching to using the factory methods in CacheManager would implicitly use cached instances when @DirtiesContext isn't necessary (such as a test that doesn't touch the cache) but close the caches after tests with @DirtiesContext.

Comment From: snicoll

The second test shouldn't fail, as it should reuse the cache from the previous one.

That's actually the reverse of what should happen. When a new ApplicationContext is created, it shouldn't reuse any existing CacheManager (so the current behaviour is legit from the perspective). Of course, the fact ehcache stores it somewhere makes thing a bit more difficult for the user but that's no reason for Spring (Boot) to twist what it would normally do.

There is @AutoConfigureCache that you ca add to your test to switch off caching entirely, you can also specify spring.cache.type=none or spring.cache.type=simple to use a simple in memory map rather than bootstrapping ehcache.

Comment From: kewne

The thing is the error produced isn't helpful, particularly since the behavior is unexpected; the point of using auto configuration is to produce a configuration which is helpful in most cases. In this case, if you rely on auto configured caching and annotate a single test with @DirtiesContext, your options are all bad: 1. use @DirtiesContext everywhere, even when some tests don't do any dirtying 2. use @AutoConfigureCache or properties to change the configuration in selected tests, even though nothing in the test requires that configuration 3. override the spring boot auto configured bean to use ehcache singleton instances

I probably jumped the gun with my suggestion but I still don't think the current behavior is the most correct: in particular, I shouldn't have to change non @DirtiesContext annotated tests to get the annotated ones to pass.

Comment From: snicoll

the point of using auto configuration is to produce a configuration which is helpful in most cases.

I don't see how that is an argument for the use case you are experiencing.

I probably jumped the gun with my suggestion but I still don't think the current behavior is the most correct: in particular, I shouldn't have to change non @DirtiesContext annotated tests to get the annotated ones to pass.

I am not 100% sure of what you mean by that. The point I was trying to make is that the auto-configuration is IMO legit: if the underlying implementation of ehcache is caching CacheManager instances per process, that's an implementation detail on their side: we shouldn't twist our auto-configuration to share resources we shouldn't be sharing in the first place. To be sure you're experiencing what I consider to be legit, please share a simple example I can run myself (a link to a zip or a repo) and we can reopen if necessary.

Comment From: kewne

See https://github.com/kewne/spring-boot-issue-14131 (and thank you for bearing with me).

The issue occurs sometimes but not others, which makes me wonder if it's a timing issue...

Comment From: snicoll

It isn't a timing issue. The SpringRunner will cache the ApplicationContext when it detects tests with a similar signature. If you set a property or if you use one of the test helper, you're going to request a slightly different ApplicationContext so the runner will create another ApplicationContext. This also happens when you use MockBean (as you're effectively changing the state of the ApplicationContext).

Your sample showcases two contexts in the suite: DirtyTests and ReallyDirtyTests are equivalent (share the same context). NonDirtyTests will require a separate application context because you've required @AutoConfigureMockMvc. If you can, create a test suite for the two first tests (select the two classes and right click run in IntelliJ IDEA). The suite will pass. If you remove @DirtiesContext it will pass as well. The order of the tests suite may be different (typically between IDE and command line) giving you the impression of a timing issue but it's all about which test runs first.

I agree the side effect of ehcache can be annoying in your scenario but this shouldn't drive us from sharing the same CacheManager if two ApplicationContext instances in the same process attempt to use Spring Boot. Rather, it should fail the way it fails now to indicate these are non-unique and there's probably something you want to do (like having dedicated configuration for them). If you have more questions, please ask on StackOverflow or come chat with us on Gitter: as mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.

Comment From: kewne

For future reference, in case someone else runs into this: I've worked around the issue by creating a JUnit test suite with just my @WebMvcTest annotated tests.

Comment From: gitbic

@snicoll Thank you spring.cache.type=simple works