/* * Copyright 2016 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.data.gemfire.config.annotation; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.springframework.data.gemfire.config.annotation.EnableEviction.EvictionPolicy; import java.util.concurrent.atomic.AtomicReference; import org.apache.geode.cache.Cache; import org.apache.geode.cache.EvictionAttributes; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.RegionFactory; import org.apache.geode.cache.util.ObjectSizer; import org.junit.After; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.gemfire.PartitionedRegionFactoryBean; import org.springframework.data.gemfire.ReplicatedRegionFactoryBean; import org.springframework.data.gemfire.eviction.EvictionActionType; import org.springframework.data.gemfire.eviction.EvictionAttributesFactoryBean; import org.springframework.data.gemfire.eviction.EvictionPolicyType; import org.springframework.data.gemfire.util.ArrayUtils; /** * Unit tests for the {@link EnableEviction} annotation and {@link EvictionConfiguration} class. * * @author John Blum * @see org.junit.Test * @see org.mockito.Mockito * @see org.springframework.data.gemfire.config.annotation.EnableEviction * @see org.springframework.data.gemfire.config.annotation.EvictionConfiguration * @see org.springframework.data.gemfire.eviction.EvictionAttributesFactoryBean * @see org.apache.geode.cache.Region * @see org.apache.geode.cache.EvictionAttributes * @since 1.9.0 */ public class EnableEvictionConfigurationUnitTests { private ConfigurableApplicationContext applicationContext; @After public void tearDown() { if (applicationContext != null) { applicationContext.close(); } } protected void assertEvictionAttributes(Region region, EvictionAttributes expectedEvictionAttributes) { assertThat(region).isNotNull(); assertThat(region.getAttributes()).isNotNull(); assertEvictionAttributes(region.getAttributes().getEvictionAttributes(), expectedEvictionAttributes); } protected void assertEvictionAttributes(EvictionAttributes actualEvictionAttributes, EvictionAttributes expectedEvictionAttributes) { assertThat(actualEvictionAttributes).isNotNull(); assertThat(actualEvictionAttributes.getAction()).isEqualTo(expectedEvictionAttributes.getAction()); assertThat(actualEvictionAttributes.getAlgorithm()).isEqualTo(expectedEvictionAttributes.getAlgorithm()); assertThat(actualEvictionAttributes.getObjectSizer()).isEqualTo(expectedEvictionAttributes.getObjectSizer()); if (!EvictionPolicyType.HEAP_PERCENTAGE.equals( EvictionPolicyType.valueOf(actualEvictionAttributes.getAlgorithm()))) { assertThat(actualEvictionAttributes.getMaximum()).isEqualTo(expectedEvictionAttributes.getMaximum()); } } @SuppressWarnings("unchecked") protected <K, V> Region<K, V> getRegion(String beanName) { return applicationContext.getBean(beanName, Region.class); } protected AnnotationConfigApplicationContext newApplicationContext(Class<?>... annotatedClasses) { return new AnnotationConfigApplicationContext(annotatedClasses); } protected EvictionAttributes newEvictionAttributes(Integer maximum, EvictionPolicyType type, EvictionActionType action, ObjectSizer... objectSizer) { EvictionAttributesFactoryBean evictionAttributesFactory = new EvictionAttributesFactoryBean(); evictionAttributesFactory.setAction(action.getEvictionAction()); evictionAttributesFactory.setObjectSizer(ArrayUtils.getFirst(objectSizer)); evictionAttributesFactory.setThreshold(maximum); evictionAttributesFactory.setType(type); evictionAttributesFactory.afterPropertiesSet(); return evictionAttributesFactory.getObject(); } @Test public void usesDefaultEvictionPolicyConfiguration() { applicationContext = newApplicationContext(DefaultEvictionPolicyConfiguration.class); EvictionAttributes defaultEvictionAttributes = EvictionAttributes.createLRUEntryAttributes(); assertEvictionAttributes(applicationContext.getBean("PartitionRegion", Region.class), defaultEvictionAttributes); assertEvictionAttributes(applicationContext.getBean("ReplicateRegion", Region.class), defaultEvictionAttributes); } @Test public void usesCustomEvictionPolicyConfiguration() { applicationContext = newApplicationContext(CustomEvictionPolicyConfiguration.class); ObjectSizer mockObjectSizer = applicationContext.getBean("mockObjectSizer", ObjectSizer.class); EvictionAttributes customEvictionAttributes = newEvictionAttributes(65536, EvictionPolicyType.MEMORY_SIZE, EvictionActionType.OVERFLOW_TO_DISK, mockObjectSizer); assertEvictionAttributes(applicationContext.getBean("PartitionRegion", Region.class), customEvictionAttributes); assertEvictionAttributes(applicationContext.getBean("ReplicateRegion", Region.class), customEvictionAttributes); } @Test public void usesRegionSpecificEvictionPolicyConfiguration() { applicationContext = newApplicationContext(RegionSpecificEvictionPolicyConfiguration.class); ObjectSizer mockObjectSizer = applicationContext.getBean("mockObjectSizer", ObjectSizer.class); EvictionAttributes partitionRegionEvictionAttributes = newEvictionAttributes(null, EvictionPolicyType.HEAP_PERCENTAGE, EvictionActionType.OVERFLOW_TO_DISK, mockObjectSizer); EvictionAttributes replicateRegionEvictionAttributes = newEvictionAttributes(10000, EvictionPolicyType.ENTRY_COUNT, EvictionActionType.LOCAL_DESTROY); assertEvictionAttributes(applicationContext.getBean("PartitionRegion", Region.class), partitionRegionEvictionAttributes); assertEvictionAttributes(applicationContext.getBean("ReplicateRegion", Region.class), replicateRegionEvictionAttributes); } @Test public void usesLastMatchingEvictionPolicyConfiguration() { applicationContext = newApplicationContext(LastMatchingWinsEvictionPolicyConfiguration.class); EvictionAttributes lastMatchingEvictionAttributes = newEvictionAttributes(99, EvictionPolicyType.ENTRY_COUNT, EvictionActionType.OVERFLOW_TO_DISK); assertEvictionAttributes(applicationContext.getBean("PartitionRegion", Region.class), lastMatchingEvictionAttributes); assertEvictionAttributes(applicationContext.getBean("ReplicateRegion", Region.class), lastMatchingEvictionAttributes); } @Configuration @SuppressWarnings("unused") static class CacheRegionConfiguration { @Bean("mockCache") @SuppressWarnings("unchecked") Cache mockCache() { Cache mockCache = mock(Cache.class); RegionFactory mockRegionFactory = mock(RegionFactory.class); final AtomicReference<EvictionAttributes> evictionAttributes = new AtomicReference<EvictionAttributes>(null); when(mockCache.createRegionFactory()).thenReturn(mockRegionFactory); when(mockRegionFactory.setEvictionAttributes(any(EvictionAttributes.class))).thenAnswer( new Answer<RegionFactory>() { @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { evictionAttributes.set(invocation.getArgument(0)); return (RegionFactory) invocation.getMock(); } } ); when(mockRegionFactory.create(anyString())).thenAnswer(new Answer<Region>() { @Override public Region answer(InvocationOnMock invocation) throws Throwable { String regionName = invocation.getArgument(0); Region mockRegion = mock(Region.class, regionName); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class, regionName.concat("Attributes")); when(mockRegion.getName()).thenReturn(regionName); when(mockRegion.getFullPath()).thenReturn(String.format("%1$s%2$s", Region.SEPARATOR, regionName)); when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes); when(mockRegionAttributes.getEvictionAttributes()).thenReturn(evictionAttributes.get()); return mockRegion; } }); return mockCache; } @Bean("PartitionRegion") PartitionedRegionFactoryBean<Object, Object> mockPartitionRegion(Cache gemfireCache) { PartitionedRegionFactoryBean<Object, Object> partitionRegion = new PartitionedRegionFactoryBean<Object, Object>(); partitionRegion.setCache(gemfireCache); partitionRegion.setClose(false); partitionRegion.setPersistent(false); return partitionRegion; } @Bean("ReplicateRegion") ReplicatedRegionFactoryBean<Object, Object> mockReplicateRegion(Cache gemfireCache) { ReplicatedRegionFactoryBean<Object, Object> replicateRegion = new ReplicatedRegionFactoryBean<Object, Object>(); replicateRegion.setCache(gemfireCache); replicateRegion.setClose(false); replicateRegion.setPersistent(false); return replicateRegion; } @Bean ObjectSizer mockObjectSizer() { return mock(ObjectSizer.class); } } @EnableEviction static class DefaultEvictionPolicyConfiguration extends CacheRegionConfiguration { } @EnableEviction(policies = @EvictionPolicy(maximum = 65536, type = EvictionPolicyType.MEMORY_SIZE, action = EvictionActionType.OVERFLOW_TO_DISK, objectSizerName = "mockObjectSizer")) static class CustomEvictionPolicyConfiguration extends CacheRegionConfiguration { } @EnableEviction(policies = { @EvictionPolicy(maximum = 85, type = EvictionPolicyType.HEAP_PERCENTAGE, action = EvictionActionType.OVERFLOW_TO_DISK, objectSizerName = "mockObjectSizer", regionNames = "PartitionRegion"), @EvictionPolicy(maximum = 10000, type = EvictionPolicyType.ENTRY_COUNT, action = EvictionActionType.LOCAL_DESTROY, regionNames = "ReplicateRegion") }) static class RegionSpecificEvictionPolicyConfiguration extends CacheRegionConfiguration { } @EnableEviction(policies = { @EvictionPolicy(maximum = 1, type = EvictionPolicyType.ENTRY_COUNT, action = EvictionActionType.LOCAL_DESTROY, objectSizerName = "mockObjectSizer", regionNames = "ReplicateRegion"), @EvictionPolicy(maximum = 99, type = EvictionPolicyType.ENTRY_COUNT, action = EvictionActionType.OVERFLOW_TO_DISK) }) static class LastMatchingWinsEvictionPolicyConfiguration extends CacheRegionConfiguration { } }