If you use org.springframework.boot.test.mock.mockito.MockBean annotation in an integration test, Spring Boot failed to load application due to an issue on duplicate cache key com.mycompany.myapp.domain.User
Stack trace: (full stack here stack.txt)
testGetExistingUser(com.mycompany.myapp.web.rest.UserResourceIntTest) Time elapsed: 0 sec <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.spri
ngframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is javax.cache.CacheException: A Cache named [com.mycompany.myapp.domain.User] already exists
Bug preventing the use of service mocks
1/ Generate a new JHipster 4.0.7 application with EHCache.
2/ Add in any integration test a @MockBean for any service.
Example: in UserServiceIntTest add the following declaration:
@MockBean
private MailService mailService;
3/ Run ./mvnw clean test
N/A
I supect the recent change to the java config EhCache and the CacheConfiguration.java.
Maybe the cache pool is not full clean between two consecutive tests.
I also notice:
The issue was not occur on the previous Jhipster v4.0.6
JHipster v4.0.7
yo jhipster:info
Welcome to the JHipster Information Sub-Generator
[email protected] D:\workspaces\jhipster\elastic
+-- UNMET PEER DEPENDENCY @angular/[email protected]
+-- UNMET PEER DEPENDENCY @angular/[email protected]
`-- [email protected]
.yo-rc.json file generated in the root folder{
"generator-jhipster": {
"jhipsterVersion": "4.0.7",
"baseName": "elastic",
"packageName": "com.mycompany.myapp",
"packageFolder": "com/mycompany/myapp",
"serverPort": "8080",
"authenticationType": "session",
"hibernateCache": "ehcache",
"clusteredHttpSession": false,
"websocket": false,
"databaseType": "sql",
"devDatabaseType": "h2Disk",
"prodDatabaseType": "postgresql",
"searchEngine": false,
"messageBroker": false,
"serviceDiscoveryType": false,
"buildTool": "maven",
"enableSocialSignIn": false,
"rememberMeKey": "069a6edee67a2da006eb9b7c2ed32aef688b40c1",
"clientFramework": "angular2",
"useSass": true,
"clientPackageManager": "yarn",
"applicationType": "monolith",
"testFrameworks": [],
"jhiPrefix": "jhi",
"enableTranslation": false
}
}
entityName.json files generated in the .jhipster directoryls: no such file or directory: .jhipster/*.json
java version "1.8.0_112"
Java(TM) SE Runtime Environment (build 1.8.0_112-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.112-b15, mixed mode)
git version 2.11.0.windows.1
node: v6.9.5
npm: 3.10.10
yeoman: 1.8.5
yarn: 0.18.1
OS x64 :
Nom du système d’exploitation Microsoft Windows 10 Famille
Version 10.0.14393 Numéro 14393
Ping @henri-tremblay as he coded this part.
As far as I remember, the cache used to be disabled during tests, and this was better for tests.
Hi Julien,
it's working if I disable the Spring cache support in test configuration as you purpose it.
In test application.yml:
spring.cache.type=none
Works until we want to test the cache mechanisms :)
Thanks you
@ndywicki, for this case, I created test profile and annotated CacheConfiguration with @Profile("!test").
This is a funny issue. The problem comes from JCache mixed with the programmatic configuration.
When @MockBean is used, it forces Spring to create multiple application context. Because a context with a mock is obviously not the same as a context without the mock.
When the first context is created, it registers a CacheManager in the JCache CachingProvider. The JCacheManagerCustomizer is then called to configure this new CacheManager.
When the second context is created, it retrieves the same CacheManager since the same URI is used. And calls the JCacheManagerCustomizer again. Fail. It was working before because the ehcache.xml was loaded once and there was no customizer.
There is no way to clean the CachingProvider. @PreDestroy is called at the end of all tests. No solution there.
Using spring.cache.type=none works perfectly since it deactivate the cache. No CachingProvider issue anymore. So if we are sure we don't want any caching during test, that's probably a good solution. It doesn't test the cache during testing but does remove a lot of entropy in the unit tests.
I was close to consider it a bug in spring-boot. They should not customize the CacheManager twice. But JCache gives no way to know a CacheManager was already existing.
The other solution is to check if the cache already exist.
@Bean
public JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -> {
createIfNotExists(cm, com.mycompany.myapp.domain.User.class.getName());
createIfNotExists(cm, com.mycompany.myapp.domain.Authority.class.getName());
createIfNotExists(cm, com.mycompany.myapp.domain.User.class.getName() + ".authorities");
createIfNotExists(cm, com.mycompany.myapp.domain.PersistentToken.class.getName());
createIfNotExists(cm, com.mycompany.myapp.domain.User.class.getName() + ".persistentTokens");
// jhipster-needle-ehcache-add-entry
};
}
private void createIfNotExists(CacheManager cacheManager, String cacheName) {
if(cacheManager.getCache(cacheName) == null) {
cacheManager.createCache(cacheName, cacheConfiguration);
}
}
The bad side of it is that it is production code hacked to work with tests. But it is not a none sense either.
Please tell me what you prefer and I will do a pull-request accordingly.
I would just do spring.cache.type=none as:
I prefer to have the cache disabled when I do my tests - then of course
there could be a very long discussion here - so that's also my favorite
solution.
Le 4 mars 2017 5:16 AM, "Henri Tremblay" notifications@github.com a
écrit :
This is a funny issue. The problem comes from JCache mixed with the
programmatic configuration.
When @MockBean is used, it forces Spring to create multiple application
context. Because a context with a mock is obviously not the same as a
context without the mock.
When the first context is created, it registers a CacheManager in the
JCache CachingProvider. The JCacheManagerCustomizer is then called to
configure this new CacheManager.
When the second context is created, it retrieves the same CacheManager
since the same URI is used. And calls the JCacheManagerCustomizer again.
Fail. It was working before because the ehcache.xml was loaded once and
there was no customizer.
There is no way to clean the CachingProvider. @PreDestroy is called at the
end of all tests. No solution there.
Using spring.cache.type=none works perfectly since it deactivate the cache.
No CachingProvider issue anymore. So if we are sure we don't want any
caching during test, that's probably a good solution. It doesn't test the
cache during testing but does remove a lot of entropy in the unit tests.
I was close to consider it a bug in spring-boot. They should not customize
the CacheManager twice. But JCache gives no way to know a CacheManager was
already existing.
The other solution is to check if the cache already exist.
@Beanpublic JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -> {
createIfNotExists(cm, com.mycompany.myapp.domain.User.class.getName());
createIfNotExists(cm,
com.mycompany.myapp.domain.Authority.class.getName());
createIfNotExists(cm,
com.mycompany.myapp.domain.User.class.getName() + ".authorities");
createIfNotExists(cm,
com.mycompany.myapp.domain.PersistentToken.class.getName());
createIfNotExists(cm,
com.mycompany.myapp.domain.User.class.getName() +
".persistentTokens");
// jhipster-needle-ehcache-add-entry
};
}
private void createIfNotExists(CacheManager cacheManager, String cacheName) {
if(cacheManager.getCache(cacheName) == null) {
cacheManager.createCache(cacheName, cacheConfiguration);
}
}
The bad side of it is that it is production code hacked to work with tests.
But it is not a none sense either.
Please tell me what you prefer and I will do a pull-request accordingly.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/jhipster/generator-jhipster/issues/5354#issuecomment-284125968,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AATVoyHE24sDjD08g9GDzQ7X4Yfo18eRks5riOW0gaJpZM4MSueb
.
Most helpful comment
This is a funny issue. The problem comes from JCache mixed with the programmatic configuration.
When
@MockBeanis used, it forces Spring to create multiple application context. Because a context with a mock is obviously not the same as a context without the mock.When the first context is created, it registers a
CacheManagerin the JCacheCachingProvider. TheJCacheManagerCustomizeris then called to configure this newCacheManager.When the second context is created, it retrieves the same
CacheManagersince the same URI is used. And calls theJCacheManagerCustomizeragain. Fail. It was working before because theehcache.xmlwas loaded once and there was no customizer.There is no way to clean the
CachingProvider.@PreDestroyis called at the end of all tests. No solution there.Using
spring.cache.type=noneworks perfectly since it deactivate the cache. NoCachingProviderissue anymore. So if we are sure we don't want any caching during test, that's probably a good solution. It doesn't test the cache during testing but does remove a lot of entropy in the unit tests.I was close to consider it a bug in spring-boot. They should not customize the
CacheManagertwice. But JCache gives no way to know aCacheManagerwas already existing.The other solution is to check if the cache already exist.
The bad side of it is that it is production code hacked to work with tests. But it is not a none sense either.
Please tell me what you prefer and I will do a pull-request accordingly.