From 3e6a9868aa587de630169d33b58bb48529c0d8ae Mon Sep 17 00:00:00 2001 From: John Blum Date: Wed, 25 Sep 2019 20:56:00 -0700 Subject: [PATCH] SGF-883 - Add support for @CacheConfig in @EnableCachingDefinedRegions. --- .../CachingDefinedRegionsConfiguration.java | 3 +- ...CacheConfigCacheNamesIntegrationTests.java | 223 ++++++++++++++++++ ...CacheConfigCacheNamesIntegrationTests.java | 185 +++++++++++++++ 3 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConsidersCacheConfigCacheNamesIntegrationTests.java create mode 100644 src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsUsesCacheConfigCacheNamesIntegrationTests.java diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java index ff9f2eb6..0b0e3803 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java @@ -44,6 +44,7 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; @@ -447,7 +448,7 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig @Override @SuppressWarnings("unchecked") protected Class[] getClassCacheAnnotationTypes() { - return append(getMethodCacheAnnotationTypes(), Caching.class); + return append(getMethodCacheAnnotationTypes(), CacheConfig.class, Caching.class); } @Override diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConsidersCacheConfigCacheNamesIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConsidersCacheConfigCacheNamesIntegrationTests.java new file mode 100644 index 00000000..640d111b --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConsidersCacheConfigCacheNamesIntegrationTests.java @@ -0,0 +1,223 @@ +/* + * Copyright 2019 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.data.gemfire.config.annotation; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.Region; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMockObjects; +import org.springframework.data.gemfire.util.CollectionUtils; +import org.springframework.stereotype.Service; + +/** + * Integration Tests for {@link EnableCachingDefinedRegions} and {@link CachingDefinedRegionsConfiguration} asserting + * that the annotation config supports the Spring Cache Abstractions {@link CacheConfig} annotation. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.cache.Region + * @see org.springframework.cache.annotation.CacheConfig + * @see org.springframework.cache.annotation.Cacheable + * @see org.springframework.context.ConfigurableApplicationContext + * @see org.springframework.context.annotation.AnnotationConfigApplicationContext + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.annotation.Configuration + * @see org.springframework.data.gemfire.config.annotation.EnableCachingDefinedRegions + * @see org.springframework.data.gemfire.config.annotation.CachingDefinedRegionsConfiguration + * @see org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMockObjects + * @see org.springframework.stereotype.Service + * @see Add support for @CacheConfig in @EnableCachingDefinedRegions + * @since 2.2.0 + */ +@SuppressWarnings("unused") +public class CachingDefinedRegionsConsidersCacheConfigCacheNamesIntegrationTests { + + private ConfigurableApplicationContext applicationContext; + + @After + public void closeApplicationContext() { + Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close); + } + + private ConfigurableApplicationContext newApplicationContext(Class... annotatedClasses) { + + AnnotationConfigApplicationContext applicationContext = + new AnnotationConfigApplicationContext(); + + applicationContext.register(annotatedClasses); + applicationContext.registerShutdownHook(); + applicationContext.refresh(); + + this.applicationContext = applicationContext; + + return applicationContext; + } + + private Set resolveCacheRegionNames(Class... annotatedClasses) { + + newApplicationContext(annotatedClasses); + + GemFireCache cache = this.applicationContext.getBean(GemFireCache.class); + + assertThat(cache).isNotNull(); + + return CollectionUtils.nullSafeSet(cache.rootRegions()).stream() + .filter(Objects::nonNull) + .map(Region::getName) + .collect(Collectors.toSet()); + } + + @Test + public void testServiceOneCacheRegionsAreCorrect() { + assertThat(resolveCacheRegionNames(TestConfigurationOne.class)).containsExactlyInAnyOrder("A", "B"); + } + + @Test + public void testServiceTwoCacheRegionsAreCorrect() { + assertThat(resolveCacheRegionNames(TestConfigurationTwo.class)).containsExactlyInAnyOrder("A", "B"); + } + + @Test + public void testServiceThreeCacheRegionsAreCorrect() { + assertThat(resolveCacheRegionNames(TestConfigurationThree.class)) + .containsExactlyInAnyOrder("A", "B", "C"); + } + + @Test + public void testServiceFourCacheRegionsAreCorrect() { + assertThat(resolveCacheRegionNames(TestConfigurationFour.class)) + .containsExactlyInAnyOrder("A", "B", "C", "D", "F"); + } + + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableCachingDefinedRegions + static class TestConfigurationOne { + + @Bean + TestServiceOne testServiceOne() { + return new TestServiceOne(); + } + } + + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableCachingDefinedRegions + static class TestConfigurationTwo { + + @Bean + TestServiceTwo testServiceTwo() { + return new TestServiceTwo(); + } + } + + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableCachingDefinedRegions + static class TestConfigurationThree { + + @Bean + TestServiceThree testServiceThree() { + return new TestServiceThree(); + } + } + + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableCachingDefinedRegions + static class TestConfigurationFour { + + @Bean + TestServiceFour testServiceFour() { + return new TestServiceFour(); + } + } + + @Service + @CacheConfig(cacheNames = { "A", "B" }) + static class TestServiceOne { + + public Object cacheableMethodOne() { + return "ONE"; + } + + public Object cacheableMethodTwo() { + return "TWO"; + } + } + + @Service + @CacheConfig(cacheNames = { "A", "B" }) + static class TestServiceTwo { + + @Cacheable + public Object cacheableMethodOne() { + return "ONE"; + } + + @Cacheable + public Object cacheableMethodTwo() { + return "TWO"; + } + } + + @Service + @CacheConfig(cacheNames = { "A", "B" }) + static class TestServiceThree { + + @Cacheable + public Object cacheableMethodOne() { + return "ONE"; + } + + @Cacheable("C") + public Object cacheableMethodTwo() { + return "TWO"; + } + } + + @Service + @CacheConfig(cacheNames = { "A", "B" }) + static class TestServiceFour { + + @Cacheable("C") + public Object cacheableMethodOne() { + return "ONE"; + } + + @Cacheable(cacheNames = { "A", "C", "D", "F" }) + public Object cacheableMethodTwo() { + return "TWO"; + } + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsUsesCacheConfigCacheNamesIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsUsesCacheConfigCacheNamesIntegrationTests.java new file mode 100644 index 00000000..b57f8157 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsUsesCacheConfigCacheNamesIntegrationTests.java @@ -0,0 +1,185 @@ +/* + * Copyright 2019 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.data.gemfire.config.annotation; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.annotation.Resource; + +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.ClientCache; +import org.apache.geode.cache.client.ClientRegionShortcut; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Bean; +import org.springframework.data.gemfire.util.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Integration Tests for {@link EnableCachingDefinedRegions} and {@link CachingDefinedRegionsConfiguration} asserting + * that the annotation config supports the Spring Cache Abstractions {@link CacheConfig} annotation. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.Region + * @see org.apache.geode.cache.client.ClientCache + * @see org.springframework.cache.annotation.CacheConfig + * @see org.springframework.cache.annotation.Cacheable + * @see org.springframework.data.gemfire.config.annotation.EnableCachingDefinedRegions + * @see org.springframework.data.gemfire.config.annotation.CachingDefinedRegionsConfiguration + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @see Add support for @CacheConfig in @EnableCachingDefinedRegions + * @since 2.2.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +@SuppressWarnings("unused") +public class CachingDefinedRegionsUsesCacheConfigCacheNamesIntegrationTests { + + private static final String LOG_LEVEL = "error"; + + @Autowired + private ClientCache clientCache; + + @Autowired + private TestCacheableService service; + + @Resource(name = "A") + private Region a; + + @Resource(name = "B") + private Region b; + + @Resource(name = "C") + private Region c; + + @Resource(name = "D") + private Region d; + + @Before + public void assertClientCacheAndRegionConfiguration() { + + assertThat(this.clientCache).isNotNull(); + + assertThat(this.clientCache.getName()) + .isEqualTo(CachingDefinedRegionsUsesCacheConfigCacheNamesIntegrationTests.class.getSimpleName()); + + assertThat(CollectionUtils.nullSafeSet(this.clientCache.rootRegions()).stream() + .filter(Objects::nonNull) + .map(Region::getName) + .collect(Collectors.toSet())).containsExactlyInAnyOrder("A", "B", "C", "D"); + + Arrays.asList(this.a, this.b, this.c, this.d).forEach(region -> { + assertThat(region).isNotNull(); + assertThat(region).isEmpty(); + }); + } + + @After + public void clearRegions() { + Arrays.asList(this.a, this.b, this.c, this.d).forEach(Region::clear); + } + + @Test + public void testNonCacheableMethodCachesNothing() { + + assertThat(this.service.nonCacheableMethod("0")).isEqualTo("TEST"); + + Arrays.asList(this.a, this.b, this.c, this.d).forEach(region -> { + assertThat(region).doesNotContainKey("0"); + assertThat(region).isEmpty(); + }); + + } + + @Test + public void cacheableMethodOneCachesToAAndB() { + + assertThat(this.service.cacheableMethodOne("2")).isEqualTo("ONE"); + + Arrays.asList(this.a, this.b).forEach(region -> assertThat(region).containsKey("2")); + Arrays.asList(this.c, this.d).forEach(region -> assertThat(region).isEmpty()); + } + + @Test + public void cacheableMethodTwoCachesToCOnly() { + + + assertThat(this.service.cacheableMethodTwo("3")).isEqualTo("TWO"); + + Collections.singletonList(this.c).forEach(region -> assertThat(region).containsKey("3")); + Arrays.asList(this.a, this.b, this.d).forEach(region -> assertThat(region).isEmpty()); + } + + @Test + public void cacheableMethodThreeCachesToAAndD() { + + + assertThat(this.service.cacheableMethodThree("4")).isEqualTo("THREE"); + + Arrays.asList(this.a, this.d).forEach(region -> assertThat(region).containsKey("4")); + Arrays.asList(this.b, this.c).forEach(region -> assertThat(region).isEmpty()); + } + + @ClientCacheApplication(name = "CachingDefinedRegionsUsesCacheConfigCacheNamesIntegrationTests", logLevel = LOG_LEVEL) + @EnableCachingDefinedRegions(clientRegionShortcut = ClientRegionShortcut.LOCAL) + static class TestConfiguration { + + @Bean + TestCacheableService testCachingService() { + return new TestCacheableService(); + } + } + + @Service + @CacheConfig(cacheNames = { "A", "B" }) + static class TestCacheableService { + + public Object nonCacheableMethod(String key) { + return "TEST"; + } + + @Cacheable + public Object cacheableMethodOne(String key) { + return "ONE"; + } + + @Cacheable("C") + public Object cacheableMethodTwo(String key) { + return "TWO"; + } + + @Cacheable({ "A", "D" }) + public Object cacheableMethodThree(String key) { + return "THREE"; + } + } +}