/*
* Copyright 2012-2017 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
*
* 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.springframework.boot.autoconfigure.cache;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.cache.Caching;
import javax.cache.configuration.CompleteConfiguration;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.expiry.CreatedExpiryPolicy;
import javax.cache.expiry.Duration;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.bucket.BucketManager;
import com.couchbase.client.spring.cache.CouchbaseCache;
import com.couchbase.client.spring.cache.CouchbaseCacheManager;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.CaffeineSpec;
import com.hazelcast.cache.HazelcastCachingProvider;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.spring.cache.HazelcastCacheManager;
import net.sf.ehcache.Status;
import org.ehcache.jsr107.EhcacheCachingProvider;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.jcache.embedded.JCachingProvider;
import org.infinispan.spring.provider.SpringEmbeddedCacheManager;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.autoconfigure.cache.support.MockCachingProvider;
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
import org.springframework.boot.junit.runner.classpath.ClassPathExclusions;
import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.cache.support.NoOpCacheManager;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link CacheAutoConfiguration}.
*
* @author Stephane Nicoll
* @author EddĂș MelĂ©ndez
*/
@RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions("hazelcast-client-*.jar")
public class CacheAutoConfigurationTests {
@Rule
public final ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context;
@After
public void tearDown() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void noEnableCaching() {
load(EmptyConfiguration.class);
this.thrown.expect(NoSuchBeanDefinitionException.class);
this.context.getBean(CacheManager.class);
}
@Test
public void cacheManagerBackOff() {
load(CustomCacheManagerConfiguration.class);
ConcurrentMapCacheManager cacheManager = validateCacheManager(
ConcurrentMapCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("custom1");
}
@Test
public void cacheManagerFromSupportBackOff() {
load(CustomCacheManagerFromSupportConfiguration.class);
ConcurrentMapCacheManager cacheManager = validateCacheManager(
ConcurrentMapCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("custom1");
}
@Test
public void cacheResolverFromSupportBackOff() throws Exception {
load(CustomCacheResolverFromSupportConfiguration.class);
this.thrown.expect(NoSuchBeanDefinitionException.class);
this.context.getBean(CacheManager.class);
}
@Test
public void customCacheResolverCanBeDefined() throws Exception {
load(SpecificCacheResolverConfiguration.class, "spring.cache.type=simple");
validateCacheManager(ConcurrentMapCacheManager.class);
assertThat(this.context.getBeansOfType(CacheResolver.class)).hasSize(1);
}
@Test
public void notSupportedCachingMode() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("Failed to bind properties under 'spring.cache.type'");
load(DefaultCacheConfiguration.class, "spring.cache.type=foobar");
}
@Test
public void simpleCacheExplicit() {
load(DefaultCacheConfiguration.class, "spring.cache.type=simple");
ConcurrentMapCacheManager cacheManager = validateCacheManager(
ConcurrentMapCacheManager.class);
assertThat(cacheManager.getCacheNames()).isEmpty();
}
@Test
public void simpleCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "simple",
"allCacheManagerCustomizer", "simpleCacheManagerCustomizer");
}
@Test
public void simpleCacheExplicitWithCacheNames() {
load(DefaultCacheConfiguration.class, "spring.cache.type=simple",
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
ConcurrentMapCacheManager cacheManager = validateCacheManager(
ConcurrentMapCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
}
@Test
public void genericCacheWithCaches() {
load(GenericCacheConfiguration.class);
SimpleCacheManager cacheManager = validateCacheManager(SimpleCacheManager.class);
assertThat(cacheManager.getCache("first"))
.isEqualTo(this.context.getBean("firstCache"));
assertThat(cacheManager.getCache("second"))
.isEqualTo(this.context.getBean("secondCache"));
assertThat(cacheManager.getCacheNames()).hasSize(2);
}
@Test
public void genericCacheExplicit() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("No cache manager could be auto-configured");
this.thrown.expectMessage("GENERIC");
load(DefaultCacheConfiguration.class, "spring.cache.type=generic");
}
@Test
public void genericCacheWithCustomizers() {
testCustomizers(GenericCacheAndCustomizersConfiguration.class, "generic",
"allCacheManagerCustomizer", "genericCacheManagerCustomizer");
}
@Test
public void genericCacheExplicitWithCaches() {
load(GenericCacheConfiguration.class, "spring.cache.type=generic");
SimpleCacheManager cacheManager = validateCacheManager(SimpleCacheManager.class);
assertThat(cacheManager.getCache("first"))
.isEqualTo(this.context.getBean("firstCache"));
assertThat(cacheManager.getCache("second"))
.isEqualTo(this.context.getBean("secondCache"));
assertThat(cacheManager.getCacheNames()).hasSize(2);
}
@Test
public void couchbaseCacheExplicit() {
load(CouchbaseCacheConfiguration.class, "spring.cache.type=couchbase");
CouchbaseCacheManager cacheManager = validateCacheManager(
CouchbaseCacheManager.class);
assertThat(cacheManager.getCacheNames()).isEmpty();
}
@Test
public void couchbaseCacheWithCustomizers() {
testCustomizers(CouchbaseCacheAndCustomizersConfiguration.class, "couchbase",
"allCacheManagerCustomizer", "couchbaseCacheManagerCustomizer");
}
@Test
public void couchbaseCacheExplicitWithCaches() {
load(CouchbaseCacheConfiguration.class, "spring.cache.type=couchbase",
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
CouchbaseCacheManager cacheManager = validateCacheManager(
CouchbaseCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
Cache cache = cacheManager.getCache("foo");
assertThat(cache).isInstanceOf(CouchbaseCache.class);
assertThat(((CouchbaseCache) cache).getTtl()).isEqualTo(0);
assertThat(((CouchbaseCache) cache).getNativeCache())
.isEqualTo(this.context.getBean("bucket"));
}
@Test
public void couchbaseCacheExplicitWithTtl() {
load(CouchbaseCacheConfiguration.class, "spring.cache.type=couchbase",
"spring.cache.cacheNames=foo,bar",
"spring.cache.couchbase.expiration=2000");
CouchbaseCacheManager cacheManager = validateCacheManager(
CouchbaseCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
Cache cache = cacheManager.getCache("foo");
assertThat(cache).isInstanceOf(CouchbaseCache.class);
assertThat(((CouchbaseCache) cache).getTtl()).isEqualTo(2);
assertThat(((CouchbaseCache) cache).getNativeCache())
.isEqualTo(this.context.getBean("bucket"));
}
@Test
public void redisCacheExplicit() {
load(RedisCacheConfiguration.class, "spring.cache.type=redis");
RedisCacheManager cacheManager = validateCacheManager(RedisCacheManager.class);
assertThat(cacheManager.getCacheNames()).isEmpty();
assertThat((Boolean) new DirectFieldAccessor(cacheManager)
.getPropertyValue("usePrefix")).isTrue();
}
@Test
public void redisCacheWithCustomizers() {
testCustomizers(RedisCacheAndCustomizersConfiguration.class, "redis",
"allCacheManagerCustomizer", "redisCacheManagerCustomizer");
}
@Test
public void redisCacheExplicitWithCaches() {
load(RedisCacheConfiguration.class, "spring.cache.type=redis",
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
RedisCacheManager cacheManager = validateCacheManager(RedisCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
}
@Test
public void noOpCacheExplicit() {
load(DefaultCacheConfiguration.class, "spring.cache.type=none");
NoOpCacheManager cacheManager = validateCacheManager(NoOpCacheManager.class);
assertThat(cacheManager.getCacheNames()).isEmpty();
}
@Test
public void jCacheCacheNoProviderExplicit() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("No cache manager could be auto-configured");
this.thrown.expectMessage("JCACHE");
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache");
}
@Test
public void jCacheCacheWithProvider() {
String cachingProviderFqn = MockCachingProvider.class.getName();
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn);
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
assertThat(cacheManager.getCacheNames()).isEmpty();
assertThat(this.context.getBean(javax.cache.CacheManager.class))
.isEqualTo(cacheManager.getCacheManager());
}
@Test
public void jCacheCacheWithCaches() {
String cachingProviderFqn = MockCachingProvider.class.getName();
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
}
@Test
public void jCacheCacheWithCachesAndCustomConfig() {
String cachingProviderFqn = MockCachingProvider.class.getName();
load(JCacheCustomConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.cacheNames[0]=one", "spring.cache.cacheNames[1]=two");
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("one", "two");
CompleteConfiguration<?, ?> defaultCacheConfiguration = this.context
.getBean(CompleteConfiguration.class);
verify(cacheManager.getCacheManager()).createCache("one",
defaultCacheConfiguration);
verify(cacheManager.getCacheManager()).createCache("two",
defaultCacheConfiguration);
}
@Test
public void jCacheCacheWithExistingJCacheManager() {
load(JCacheCustomCacheManager.class, "spring.cache.type=jcache");
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
assertThat(cacheManager.getCacheManager())
.isEqualTo(this.context.getBean("customJCacheCacheManager"));
}
@Test
public void jCacheCacheWithUnknownProvider() {
String wrongCachingProviderFqn = "org.acme.FooBar";
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage(wrongCachingProviderFqn);
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + wrongCachingProviderFqn);
}
@Test
public void jCacheCacheWithConfig() throws IOException {
String cachingProviderFqn = MockCachingProvider.class.getName();
String configLocation = "org/springframework/boot/autoconfigure/hazelcast/hazelcast-specific.xml";
load(JCacheCustomConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.jcache.config=" + configLocation);
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
Resource configResource = new ClassPathResource(configLocation);
assertThat(cacheManager.getCacheManager().getURI())
.isEqualTo(configResource.getURI());
}
@Test
public void jCacheCacheWithWrongConfig() {
String cachingProviderFqn = MockCachingProvider.class.getName();
String configLocation = "org/springframework/boot/autoconfigure/cache/does-not-exist.xml";
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("does not exist");
this.thrown.expectMessage(configLocation);
load(JCacheCustomConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.jcache.config=" + configLocation);
}
@Test
public void ehcacheCacheWithCaches() {
load(DefaultCacheConfiguration.class, "spring.cache.type=ehcache");
EhCacheCacheManager cacheManager = validateCacheManager(
EhCacheCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("cacheTest1", "cacheTest2");
assertThat(this.context.getBean(net.sf.ehcache.CacheManager.class))
.isEqualTo(cacheManager.getCacheManager());
}
@Test
public void ehcacheCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "ehcache",
"allCacheManagerCustomizer", "ehcacheCacheManagerCustomizer");
}
@Test
public void ehcacheCacheWithConfig() {
load(DefaultCacheConfiguration.class, "spring.cache.type=ehcache",
"spring.cache.ehcache.config=cache/ehcache-override.xml");
EhCacheCacheManager cacheManager = validateCacheManager(
EhCacheCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("cacheOverrideTest1",
"cacheOverrideTest2");
}
@Test
public void ehcacheCacheWithExistingCacheManager() {
load(EhCacheCustomCacheManager.class, "spring.cache.type=ehcache");
EhCacheCacheManager cacheManager = validateCacheManager(
EhCacheCacheManager.class);
assertThat(cacheManager.getCacheManager())
.isEqualTo(this.context.getBean("customEhCacheCacheManager"));
}
@Test
public void ehcache3AsJCacheWithCaches() {
String cachingProviderFqn = EhcacheCachingProvider.class.getName();
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
}
@Test
public void ehcache3AsJCacheWithConfig() throws IOException {
String cachingProviderFqn = EhcacheCachingProvider.class.getName();
String configLocation = "ehcache3.xml";
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.jcache.config=" + configLocation);
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
Resource configResource = new ClassPathResource(configLocation);
assertThat(cacheManager.getCacheManager().getURI())
.isEqualTo(configResource.getURI());
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
}
@Test
public void hazelcastCacheExplicit() { // Fail
load(new Class[] { HazelcastAutoConfiguration.class,
DefaultCacheConfiguration.class }, "spring.cache.type=hazelcast");
HazelcastCacheManager cacheManager = validateCacheManager(
HazelcastCacheManager.class);
// NOTE: the hazelcast implementation knows about a cache in a lazy manner.
cacheManager.getCache("defaultCache");
assertThat(cacheManager.getCacheNames()).containsOnly("defaultCache");
assertThat(this.context.getBean(HazelcastInstance.class))
.isEqualTo(cacheManager.getHazelcastInstance());
}
@Test
public void hazelcastCacheWithCustomizers() {
testCustomizers(HazelcastCacheAndCustomizersConfiguration.class, "hazelcast",
"allCacheManagerCustomizer", "hazelcastCacheManagerCustomizer");
}
@Test
public void hazelcastCacheWithExistingHazelcastInstance() {
load(HazelcastCustomHazelcastInstance.class, "spring.cache.type=hazelcast");
HazelcastCacheManager cacheManager = validateCacheManager(
HazelcastCacheManager.class);
assertThat(cacheManager.getHazelcastInstance())
.isEqualTo(this.context.getBean("customHazelcastInstance"));
}
@Test
public void hazelcastCacheWithHazelcastAutoConfiguration() throws IOException {
String hazelcastConfig = "org/springframework/boot/autoconfigure/hazelcast/hazelcast-specific.xml";
load(new Class[] { HazelcastAutoConfiguration.class,
DefaultCacheConfiguration.class }, "spring.cache.type=hazelcast",
"spring.hazelcast.config=" + hazelcastConfig);
HazelcastCacheManager cacheManager = validateCacheManager(
HazelcastCacheManager.class);
HazelcastInstance hazelcastInstance = this.context
.getBean(HazelcastInstance.class);
assertThat(cacheManager.getHazelcastInstance()).isSameAs(hazelcastInstance);
assertThat(hazelcastInstance.getConfig().getConfigurationFile())
.isEqualTo(new ClassPathResource(hazelcastConfig).getFile());
assertThat(cacheManager.getCache("foobar")).isNotNull();
assertThat(cacheManager.getCacheNames()).containsOnly("foobar");
}
@Test
public void hazelcastAsJCacheWithCaches() {
String cachingProviderFqn = HazelcastCachingProvider.class.getName();
try {
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
JCacheCacheManager cacheManager = validateCacheManager(
JCacheCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
assertThat(Hazelcast.getAllHazelcastInstances()).hasSize(1);
}
finally {
Caching.getCachingProvider(cachingProviderFqn).close();
}
}
@Test
public void hazelcastAsJCacheWithConfig() throws IOException {
String cachingProviderFqn = HazelcastCachingProvider.class.getName();
try {
String configLocation = "org/springframework/boot/autoconfigure/hazelcast/hazelcast-specific.xml";
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.jcache.config=" + configLocation);
JCacheCacheManager cacheManager = validateCacheManager(
JCacheCacheManager.class);
Resource configResource = new ClassPathResource(configLocation);
assertThat(cacheManager.getCacheManager().getURI())
.isEqualTo(configResource.getURI());
assertThat(Hazelcast.getAllHazelcastInstances()).hasSize(1);
}
finally {
Caching.getCachingProvider(cachingProviderFqn).close();
}
}
@Test
public void hazelcastAsJCacheWithExistingHazelcastInstance() throws IOException {
String cachingProviderFqn = HazelcastCachingProvider.class.getName();
load(new Class[] { HazelcastAutoConfiguration.class,
DefaultCacheConfiguration.class }, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn);
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
javax.cache.CacheManager jCacheManager = cacheManager.getCacheManager();
assertThat(jCacheManager)
.isInstanceOf(com.hazelcast.cache.HazelcastCacheManager.class);
assertThat(this.context.getBeansOfType(HazelcastInstance.class)).hasSize(1);
HazelcastInstance hazelcastInstance = this.context
.getBean(HazelcastInstance.class);
assertThat(((com.hazelcast.cache.HazelcastCacheManager) jCacheManager)
.getHazelcastInstance()).isSameAs(hazelcastInstance);
assertThat(hazelcastInstance.getName()).isEqualTo("default-instance");
assertThat(Hazelcast.getAllHazelcastInstances()).hasSize(1);
}
@Test
public void infinispanCacheWithConfig() {
load(DefaultCacheConfiguration.class, "spring.cache.type=infinispan",
"spring.cache.infinispan.config=infinispan.xml");
SpringEmbeddedCacheManager cacheManager = validateCacheManager(
SpringEmbeddedCacheManager.class);
assertThat(cacheManager.getCacheNames()).contains("foo", "bar");
}
@Test
public void infinispanCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "infinispan",
"allCacheManagerCustomizer", "infinispanCacheManagerCustomizer");
}
@Test
public void infinispanCacheWithCaches() {
load(DefaultCacheConfiguration.class, "spring.cache.type=infinispan",
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
SpringEmbeddedCacheManager cacheManager = validateCacheManager(
SpringEmbeddedCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
}
@Test
public void infinispanCacheWithCachesAndCustomConfig() {
load(InfinispanCustomConfiguration.class, "spring.cache.type=infinispan",
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
SpringEmbeddedCacheManager cacheManager = validateCacheManager(
SpringEmbeddedCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
ConfigurationBuilder defaultConfigurationBuilder = this.context
.getBean(ConfigurationBuilder.class);
verify(defaultConfigurationBuilder, times(2)).build();
}
@Test
public void infinispanAsJCacheWithCaches() {
String cachingProviderFqn = JCachingProvider.class.getName();
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
}
@Test
public void infinispanAsJCacheWithConfig() throws IOException {
String cachingProviderFqn = JCachingProvider.class.getName();
String configLocation = "infinispan.xml";
load(DefaultCacheConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.jcache.config=" + configLocation);
JCacheCacheManager cacheManager = validateCacheManager(JCacheCacheManager.class);
Resource configResource = new ClassPathResource(configLocation);
assertThat(cacheManager.getCacheManager().getURI())
.isEqualTo(configResource.getURI());
}
@Test
public void jCacheCacheWithCachesAndCustomizer() {
String cachingProviderFqn = HazelcastCachingProvider.class.getName();
try {
load(JCacheWithCustomizerConfiguration.class, "spring.cache.type=jcache",
"spring.cache.jcache.provider=" + cachingProviderFqn,
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
JCacheCacheManager cacheManager = validateCacheManager(
JCacheCacheManager.class);
// see customizer
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "custom1");
}
finally {
Caching.getCachingProvider(cachingProviderFqn).close();
}
}
@Test
public void caffeineCacheWithExplicitCaches() {
load(DefaultCacheConfiguration.class, "spring.cache.type=caffeine",
"spring.cache.cacheNames=foo");
CaffeineCacheManager cacheManager = validateCacheManager(
CaffeineCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo");
Cache foo = cacheManager.getCache("foo");
foo.get("1");
// See next tests: no spec given so stats should be disabled
assertThat(((CaffeineCache) foo).getNativeCache().stats().missCount())
.isEqualTo(0L);
}
@Test
public void caffeineCacheWithCustomizers() {
testCustomizers(DefaultCacheAndCustomizersConfiguration.class, "caffeine",
"allCacheManagerCustomizer", "caffeineCacheManagerCustomizer");
}
@Test
public void caffeineCacheWithExplicitCacheBuilder() {
load(CaffeineCacheBuilderConfiguration.class, "spring.cache.type=caffeine",
"spring.cache.cacheNames=foo,bar");
validateCaffeineCacheWithStats();
}
@Test
public void caffeineCacheExplicitWithSpec() {
load(CaffeineCacheSpecConfiguration.class, "spring.cache.type=caffeine",
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
validateCaffeineCacheWithStats();
}
@Test
public void caffeineCacheExplicitWithSpecString() {
load(DefaultCacheConfiguration.class, "spring.cache.type=caffeine",
"spring.cache.caffeine.spec=recordStats",
"spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
validateCaffeineCacheWithStats();
}
private void validateCaffeineCacheWithStats() {
CaffeineCacheManager cacheManager = validateCacheManager(
CaffeineCacheManager.class);
assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
Cache foo = cacheManager.getCache("foo");
foo.get("1");
assertThat(((CaffeineCache) foo).getNativeCache().stats().missCount())
.isEqualTo(1L);
}
private <T extends CacheManager> T validateCacheManager(Class<T> type) {
CacheManager cacheManager = this.context.getBean(CacheManager.class);
assertThat(cacheManager).as("Wrong cache manager type").isInstanceOf(type);
return type.cast(cacheManager);
}
@SuppressWarnings("rawtypes")
private void testCustomizers(Class<?> config, String cacheType,
String... expectedCustomizerNames) {
load(config, "spring.cache.type=" + cacheType);
CacheManager cacheManager = validateCacheManager(CacheManager.class);
List<String> expected = new ArrayList<>();
expected.addAll(Arrays.asList(expectedCustomizerNames));
Map<String, CacheManagerTestCustomizer> map = this.context
.getBeansOfType(CacheManagerTestCustomizer.class);
for (Map.Entry<String, CacheManagerTestCustomizer> entry : map.entrySet()) {
if (expected.contains(entry.getKey())) {
expected.remove(entry.getKey());
assertThat(entry.getValue().cacheManager).isSameAs(cacheManager);
}
else {
assertThat(entry.getValue().cacheManager).isNull();
}
}
assertThat(expected).hasSize(0);
}
private void load(Class<?> config, String... environment) {
load(new Class[] { config }, environment);
}
private void load(Class<?>[] configs, String... environment) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
applicationContext.register(configs);
applicationContext.register(CacheAutoConfiguration.class);
applicationContext.refresh();
this.context = applicationContext;
}
@Configuration
static class EmptyConfiguration {
}
@Configuration
@EnableCaching
static class DefaultCacheConfiguration {
}
@Configuration
@EnableCaching
@Import(CacheManagerCustomizersConfiguration.class)
static class DefaultCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class GenericCacheConfiguration {
@Bean
public Cache firstCache() {
return new ConcurrentMapCache("first");
}
@Bean
public Cache secondCache() {
return new ConcurrentMapCache("second");
}
}
@Configuration
@Import({ GenericCacheConfiguration.class,
CacheManagerCustomizersConfiguration.class })
static class GenericCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
@Import({ HazelcastAutoConfiguration.class,
CacheManagerCustomizersConfiguration.class })
static class HazelcastCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class CouchbaseCacheConfiguration {
@Bean
public Bucket bucket() {
BucketManager bucketManager = mock(BucketManager.class);
Bucket bucket = mock(Bucket.class);
given(bucket.bucketManager()).willReturn(bucketManager);
return bucket;
}
}
@Configuration
@Import({ CouchbaseCacheConfiguration.class,
CacheManagerCustomizersConfiguration.class })
static class CouchbaseCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class RedisCacheConfiguration {
@Bean
public RedisTemplate<?, ?> redisTemplate() {
return mock(RedisTemplate.class);
}
}
@Configuration
@Import({ RedisCacheConfiguration.class, CacheManagerCustomizersConfiguration.class })
static class RedisCacheAndCustomizersConfiguration {
}
@Configuration
@EnableCaching
static class JCacheCustomConfiguration {
@Bean
public CompleteConfiguration<?, ?> defaultCacheConfiguration() {
return mock(CompleteConfiguration.class);
}
}
@Configuration
@EnableCaching
static class JCacheCustomCacheManager {
@Bean
public javax.cache.CacheManager customJCacheCacheManager() {
javax.cache.CacheManager cacheManager = mock(javax.cache.CacheManager.class);
given(cacheManager.getCacheNames())
.willReturn(Collections.<String>emptyList());
return cacheManager;
}
}
@Configuration
@EnableCaching
static class JCacheWithCustomizerConfiguration {
@Bean
JCacheManagerCustomizer myCustomizer() {
return new JCacheManagerCustomizer() {
@Override
public void customize(javax.cache.CacheManager cacheManager) {
MutableConfiguration<?, ?> config = new MutableConfiguration<>();
config.setExpiryPolicyFactory(
CreatedExpiryPolicy.factoryOf(Duration.TEN_MINUTES));
config.setStatisticsEnabled(true);
cacheManager.createCache("custom1", config);
cacheManager.destroyCache("bar");
}
};
}
}
@Configuration
@EnableCaching
static class EhCacheCustomCacheManager {
@Bean
public net.sf.ehcache.CacheManager customEhCacheCacheManager() {
net.sf.ehcache.CacheManager cacheManager = mock(
net.sf.ehcache.CacheManager.class);
given(cacheManager.getStatus()).willReturn(Status.STATUS_ALIVE);
given(cacheManager.getCacheNames()).willReturn(new String[0]);
return cacheManager;
}
}
@Configuration
@EnableCaching
static class HazelcastCustomHazelcastInstance {
@Bean
public HazelcastInstance customHazelcastInstance() {
return mock(HazelcastInstance.class);
}
}
@Configuration
@EnableCaching
static class InfinispanCustomConfiguration {
@Bean
public ConfigurationBuilder configurationBuilder() {
ConfigurationBuilder builder = mock(ConfigurationBuilder.class);
given(builder.build()).willReturn(new ConfigurationBuilder().build());
return builder;
}
}
@Configuration
@EnableCaching
static class CustomCacheManagerConfiguration {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("custom1");
}
}
@Configuration
@EnableCaching
static class CustomCacheManagerFromSupportConfiguration
extends CachingConfigurerSupport {
@Override
@Bean
// The @Bean annotation is important, see CachingConfigurerSupport Javadoc
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("custom1");
}
}
@Configuration
@EnableCaching
static class CustomCacheResolverFromSupportConfiguration
extends CachingConfigurerSupport {
@Override
@Bean
// The @Bean annotation is important, see CachingConfigurerSupport Javadoc
public CacheResolver cacheResolver() {
return new CacheResolver() {
@Override
public Collection<? extends Cache> resolveCaches(
CacheOperationInvocationContext<?> context) {
return Collections.singleton(mock(Cache.class));
}
};
}
}
@Configuration
@EnableCaching
static class SpecificCacheResolverConfiguration {
@Bean
public CacheResolver myCacheResolver() {
return mock(CacheResolver.class);
}
}
@Configuration
@EnableCaching
static class CaffeineCacheBuilderConfiguration {
@Bean
Caffeine<Object, Object> cacheBuilder() {
return Caffeine.newBuilder().recordStats();
}
}
@Configuration
@EnableCaching
static class CaffeineCacheSpecConfiguration {
@Bean
CaffeineSpec caffeineSpec() {
return CaffeineSpec.parse("recordStats");
}
}
@Configuration
static class CacheManagerCustomizersConfiguration {
@Bean
public CacheManagerCustomizer<CacheManager> allCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<CacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> simpleCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<ConcurrentMapCacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<SimpleCacheManager> genericCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<SimpleCacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<CouchbaseCacheManager> couchbaseCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<CouchbaseCacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<RedisCacheManager> redisCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<RedisCacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<EhCacheCacheManager> ehcacheCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<EhCacheCacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<HazelcastCacheManager> hazelcastCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<HazelcastCacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<SpringEmbeddedCacheManager> infinispanCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<SpringEmbeddedCacheManager>() {
};
}
@Bean
public CacheManagerCustomizer<CaffeineCacheManager> caffeineCacheManagerCustomizer() {
return new CacheManagerTestCustomizer<CaffeineCacheManager>() {
};
}
}
static abstract class CacheManagerTestCustomizer<T extends CacheManager>
implements CacheManagerCustomizer<T> {
private T cacheManager;
@Override
public void customize(T cacheManager) {
if (this.cacheManager != null) {
throw new IllegalStateException("Customized invoked twice");
}
this.cacheManager = cacheManager;
}
}
}