diff --git a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index 8e5bf563..7f8350e0 100644 --- a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -273,7 +273,7 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, beanFactoryLocator.afterPropertiesSet(); } - final ClassLoader originalThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); + final ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); try { // use bean ClassLoader to load Spring configured, GemFire Declarable classes @@ -296,7 +296,7 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, return cache; } finally { - Thread.currentThread().setContextClassLoader(originalThreadContextClassLoader); + Thread.currentThread().setContextClassLoader(currentThreadContextClassLoader); } } @@ -609,66 +609,6 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, this.useBeanFactoryLocator = usage; } - /** - * Controls whether auto-reconnect functionality introduced in GemFire 8 is enabled or not. - * - * @param enableAutoReconnect a boolean value to enable/disable auto-reconnect functionality. - * @since GemFire 8.0 - */ - public void setEnableAutoReconnect(Boolean enableAutoReconnect) { - this.enableAutoReconnect = enableAutoReconnect; - } - - /** - * Sets the {@link PdxSerializable} for this cache. Applicable on GemFire - * 6.6 or higher. The argument is of type object for compatibility with - * GemFire 6.5. - * - * @param serializer pdx serializer configured for this cache. - */ - public void setPdxSerializer(Object serializer) { - this.pdxSerializer = serializer; - } - - /** - * Sets the object preference to PdxInstance. Applicable on GemFire 6.6 or higher. - * - * @param pdxReadSerialized a boolean value indicating the PDX instance should be returned from Region.get(key) - * when available. - */ - public void setPdxReadSerialized(Boolean pdxReadSerialized) { - this.pdxReadSerialized = pdxReadSerialized; - } - - /** - * Controls whether type metadata for PDX objects is persisted to disk. Applicable on GemFire 6.6 or higher. - * - * @param pdxPersistent a boolean value indicating that PDX type meta-data should be persisted to disk. - */ - public void setPdxPersistent(Boolean pdxPersistent) { - this.pdxPersistent = pdxPersistent; - } - - /** - * Controls whether pdx ignores fields that were unread during - * deserialization. Applicable on GemFire 6.6 or higher. - * - * @param pdxIgnoreUnreadFields the pdxIgnoreUnreadFields to set - */ - public void setPdxIgnoreUnreadFields(Boolean pdxIgnoreUnreadFields) { - this.pdxIgnoreUnreadFields = pdxIgnoreUnreadFields; - } - - /** - * Set the disk store that is used for PDX meta data. Applicable on GemFire - * 6.6 or higher. - * - * @param pdxDiskStoreName the pdxDiskStoreName to set - */ - public void setPdxDiskStoreName(String pdxDiskStoreName) { - this.pdxDiskStoreName = pdxDiskStoreName; - } - /** * Set whether the Cache should be closed. * @@ -696,6 +636,25 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, this.criticalHeapPercentage = criticalHeapPercentage; } + /** + * Sets an instance of the DynamicRegionSupport to support Dynamic Regions in this GemFire Cache. + * + * @param dynamicRegionSupport the DynamicRegionSupport class to setup Dynamic Regions in this Cache. + */ + public void setDynamicRegionSupport(DynamicRegionSupport dynamicRegionSupport) { + this.dynamicRegionSupport = dynamicRegionSupport; + } + + /** + * Controls whether auto-reconnect functionality introduced in GemFire 8 is enabled or not. + * + * @param enableAutoReconnect a boolean value to enable/disable auto-reconnect functionality. + * @since GemFire 8.0 + */ + public void setEnableAutoReconnect(Boolean enableAutoReconnect) { + this.enableAutoReconnect = enableAutoReconnect; + } + /** * Set the Cache's eviction heap percentage attribute. * @@ -705,6 +664,23 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, this.evictionHeapPercentage = evictionHeapPercentage; } + /** + * Requires GemFire 7.0 or higher + * @param gatewayConflictResolver defined as Object in the signature for backward + * compatibility with Gemfire 6 compatibility. This must be an instance of + * {@link com.gemstone.gemfire.cache.util.GatewayConflictResolver} + */ + public void setGatewayConflictResolver(Object gatewayConflictResolver) { + this.gatewayConflictResolver = gatewayConflictResolver; + } + + /** + * @param jndiDataSources the list of configured JndiDataSources to use with this Cache. + */ + public void setJndiDataSources(List jndiDataSources) { + this.jndiDataSources = jndiDataSources; + } + /** * Sets the number of seconds for implicit and explicit object lock leases to timeout. * @@ -735,6 +711,56 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, this.messageSyncInterval = messageSyncInterval; } + /** + * Sets the {@link PdxSerializable} for this cache. Applicable on GemFire + * 6.6 or higher. The argument is of type object for compatibility with + * GemFire 6.5. + * + * @param serializer pdx serializer configured for this cache. + */ + public void setPdxSerializer(Object serializer) { + this.pdxSerializer = serializer; + } + + /** + * Sets the object preference to PdxInstance. Applicable on GemFire 6.6 or higher. + * + * @param pdxReadSerialized a boolean value indicating the PDX instance should be returned from Region.get(key) + * when available. + */ + public void setPdxReadSerialized(Boolean pdxReadSerialized) { + this.pdxReadSerialized = pdxReadSerialized; + } + + /** + * Controls whether type metadata for PDX objects is persisted to disk. Applicable on GemFire 6.6 or higher. + * + * @param pdxPersistent a boolean value indicating that PDX type meta-data should be persisted to disk. + */ + public void setPdxPersistent(Boolean pdxPersistent) { + this.pdxPersistent = pdxPersistent; + } + + /** + * Controls whether pdx ignores fields that were unread during + * deserialization. Applicable on GemFire 6.6 or higher. + * + * @param pdxIgnoreUnreadFields the pdxIgnoreUnreadFields to set + */ + public void setPdxIgnoreUnreadFields(Boolean pdxIgnoreUnreadFields) { + this.pdxIgnoreUnreadFields = pdxIgnoreUnreadFields; + } + + /** + * Set the disk store that is used for PDX meta data. Applicable on GemFire + * 6.6 or higher. + * + * @param pdxDiskStoreName the pdxDiskStoreName to set + */ + public void setPdxDiskStoreName(String pdxDiskStoreName) { + this.pdxDiskStoreName = pdxDiskStoreName; + } + /** * Set the number of seconds a netSearch operation can wait for data before timing out. * @@ -766,32 +792,6 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, this.transactionWriter = transactionWriter; } - /** - * Sets an instance of the DynamicRegionSupport to support Dynamic Regions in this GemFire Cache. - * - * @param dynamicRegionSupport the DynamicRegionSupport class to setup Dynamic Regions in this Cache. - */ - public void setDynamicRegionSupport(DynamicRegionSupport dynamicRegionSupport) { - this.dynamicRegionSupport = dynamicRegionSupport; - } - - /** - * Requires GemFire 7.0 or higher - * @param gatewayConflictResolver defined as Object in the signature for backward - * compatibility with Gemfire 6 compatibility. This must be an instance of - * {@link com.gemstone.gemfire.cache.util.GatewayConflictResolver} - */ - public void setGatewayConflictResolver(Object gatewayConflictResolver) { - this.gatewayConflictResolver = gatewayConflictResolver; - } - - /** - * @param jndiDataSources the list of configured JndiDataSources to use with this Cache. - */ - public void setJndiDataSources(List jndiDataSources) { - this.jndiDataSources = jndiDataSources; - } - /** * Sets the state of the use-shared-configuration GemFire distribution config setting. * @@ -893,6 +893,13 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, return criticalHeapPercentage; } + /** + * @return the dynamicRegionSupport + */ + public DynamicRegionSupport getDynamicRegionSupport() { + return dynamicRegionSupport; + } + /** * Gets the value for the auto-reconnect setting. * @@ -910,6 +917,20 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, return evictionHeapPercentage; } + /** + * @return the gatewayConflictResolver + */ + public Object getGatewayConflictResolver() { + return gatewayConflictResolver; + } + + /** + * @return the list of configured JndiDataSources. + */ + public List getJndiDataSources() { + return jndiDataSources; + } + /** * @return the pdxSerializer */ @@ -987,27 +1008,6 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, return transactionWriter; } - /** - * @return the dynamicRegionSupport - */ - public DynamicRegionSupport getDynamicRegionSupport() { - return dynamicRegionSupport; - } - - /** - * @return the gatewayConflictResolver - */ - public Object getGatewayConflictResolver() { - return gatewayConflictResolver; - } - - /** - * @return the list of configured JndiDataSources. - */ - public List getJndiDataSources() { - return jndiDataSources; - } - /** * Gets the value fo the use-shared-configuration GemFire setting. * diff --git a/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java new file mode 100644 index 00000000..01fe04ba --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java @@ -0,0 +1,508 @@ +/* + * Copyright 2010-2013 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.Test; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.access.BeanFactoryReference; +import org.springframework.core.io.Resource; +import org.springframework.data.util.ReflectionUtils; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.CacheFactory; +import com.gemstone.gemfire.cache.CacheTransactionManager; +import com.gemstone.gemfire.cache.GemFireCache; +import com.gemstone.gemfire.cache.TransactionListener; +import com.gemstone.gemfire.cache.TransactionWriter; +import com.gemstone.gemfire.cache.control.ResourceManager; +import com.gemstone.gemfire.cache.util.GatewayConflictResolver; +import com.gemstone.gemfire.distributed.DistributedMember; +import com.gemstone.gemfire.distributed.DistributedSystem; +import com.gemstone.gemfire.distributed.Role; +import com.gemstone.gemfire.pdx.PdxSerializer; + +/** + * The CacheFactoryBeanTest class is a test suite of test cases testing the contract and functionality + * of the CacheFactoryBean class. + * + * @author John Blum + * @see org.mockito.Mockito + * @see org.junit.Test + * @see org.springframework.data.gemfire.CacheFactoryBean + * @see com.gemstone.gemfire.cache.Cache + * @since 1.7.0 + */ +public class CacheFactoryBeanTest { + + @Test + public void testAfterPropertiesSet() throws Exception { + BeanFactory mockBeanFactory = mock(BeanFactory.class, "SpringBeanFactory"); + Cache mockCache = mock(Cache.class, "GemFireCache"); + CacheTransactionManager mockCacheTransactionManager = mock(CacheTransactionManager.class, "GemFireTransactionManager"); + DistributedMember mockDistributedMember = mock(DistributedMember.class, "GemFireDistributedMember"); + DistributedSystem mockDistributedSystem = mock(DistributedSystem.class, "GemFireDistributedSystem"); + GatewayConflictResolver mockGatewayConflictResolver = mock(GatewayConflictResolver.class, "GemFireGatewayConflictResolver"); + PdxSerializer mockPdxSerializer = mock(PdxSerializer.class, "GemFirePdxSerializer"); + Resource mockCacheXml = mock(Resource.class, "GemFireCacheXml"); + ResourceManager mockResourceManager = mock(ResourceManager.class, "GemFireResourceManager"); + TransactionListener mockTransactionLister = mock(TransactionListener.class, "GemFireTransactionListener"); + TransactionWriter mockTransactionWriter = mock(TransactionWriter.class, "GemFireTransactionWriter"); + + final CacheFactory mockCacheFactory = mock(CacheFactory.class, "GemFireCacheFactory"); + + when(mockCacheFactory.create()).thenReturn(mockCache); + when(mockCache.getCacheTransactionManager()).thenReturn(mockCacheTransactionManager); + when(mockCache.getDistributedSystem()).thenReturn(mockDistributedSystem); + when(mockCache.getResourceManager()).thenReturn(mockResourceManager); + when(mockCacheXml.getInputStream()).thenReturn(mock(InputStream.class)); + when(mockDistributedSystem.getDistributedMember()).thenReturn(mockDistributedMember); + when(mockDistributedSystem.getName()).thenReturn("MockDistributedSystem"); + when(mockDistributedMember.getId()).thenReturn("MockDistributedMember"); + when(mockDistributedMember.getGroups()).thenReturn(Collections.emptyList()); + when(mockDistributedMember.getRoles()).thenReturn(Collections.emptySet()); + when(mockDistributedMember.getHost()).thenReturn("skullbox"); + when(mockDistributedMember.getProcessId()).thenReturn(12345); + + final ClassLoader expectedThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); + + final Properties gemfireProperties = new Properties(); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() { + @Override protected Object createFactory(final Properties actualGemfireProperties) { + assertSame(gemfireProperties, actualGemfireProperties); + assertSame(ClassLoader.getSystemClassLoader(), getBeanClassLoader()); + return mockCacheFactory; + } + }; + + cacheFactoryBean.setBeanClassLoader(ClassLoader.getSystemClassLoader()); + cacheFactoryBean.setBeanFactory(mockBeanFactory); + cacheFactoryBean.setBeanName("TestGemFireCache"); + cacheFactoryBean.setCacheXml(mockCacheXml); + cacheFactoryBean.setCopyOnRead(true); + cacheFactoryBean.setCriticalHeapPercentage(0.90f); + cacheFactoryBean.setDynamicRegionSupport(null); + cacheFactoryBean.setEnableAutoReconnect(false); + cacheFactoryBean.setEvictionHeapPercentage(0.75f); + cacheFactoryBean.setGatewayConflictResolver(mockGatewayConflictResolver); + cacheFactoryBean.setJndiDataSources(null); + cacheFactoryBean.setLazyInitialize(false); + cacheFactoryBean.setLockLease(15000); + cacheFactoryBean.setLockTimeout(5000); + cacheFactoryBean.setMessageSyncInterval(20000); + cacheFactoryBean.setPdxSerializer(mockPdxSerializer); + cacheFactoryBean.setPdxReadSerialized(true); + cacheFactoryBean.setPdxPersistent(true); + cacheFactoryBean.setPdxIgnoreUnreadFields(false); + cacheFactoryBean.setPdxDiskStoreName("TestPdxDiskStore"); + cacheFactoryBean.setProperties(gemfireProperties); + cacheFactoryBean.setSearchTimeout(45000); + cacheFactoryBean.setTransactionListeners(Collections.singletonList(mockTransactionLister)); + cacheFactoryBean.setTransactionWriter(mockTransactionWriter); + + assertTrue(gemfireProperties.isEmpty()); + + cacheFactoryBean.afterPropertiesSet(); + + assertEquals(2, gemfireProperties.size()); + assertTrue(gemfireProperties.containsKey("disable-auto-reconnect")); + assertTrue(gemfireProperties.containsKey("use-cluster-configuration")); + assertEquals("true", gemfireProperties.getProperty("disable-auto-reconnect")); + assertEquals("false", gemfireProperties.getProperty("use-cluster-configuration")); + assertSame(expectedThreadContextClassLoader, Thread.currentThread().getContextClassLoader()); + + GemfireBeanFactoryLocator beanFactoryLocator = cacheFactoryBean.getBeanFactoryLocator(); + + assertNotNull(beanFactoryLocator); + + BeanFactoryReference beanFactoryReference = beanFactoryLocator.useBeanFactory("TestGemFireCache"); + + assertNotNull(beanFactoryReference); + assertSame(mockBeanFactory, beanFactoryReference.getFactory()); + + verify(mockCacheFactory, times(1)).setPdxDiskStore(eq("TestPdxDiskStore")); + verify(mockCacheFactory, times(1)).setPdxIgnoreUnreadFields(eq(false)); + verify(mockCacheFactory, times(1)).setPdxPersistent(eq(true)); + verify(mockCacheFactory, times(1)).setPdxReadSerialized(eq(true)); + verify(mockCacheFactory, times(1)).setPdxSerializer(eq(mockPdxSerializer)); + verify(mockCacheFactory, times(1)).create(); + verify(mockCache, times(1)).loadCacheXml(any(InputStream.class)); + verify(mockCache, times(1)).setCopyOnRead(eq(true)); + verify(mockCache, times(1)).setGatewayConflictResolver(same(mockGatewayConflictResolver)); + verify(mockCache, times(1)).setLockLease(eq(15000)); + verify(mockCache, times(1)).setLockTimeout(eq(5000)); + verify(mockCache, times(1)).setMessageSyncInterval(eq(20000)); + verify(mockCache, times(1)).setSearchTimeout(eq(45000)); + verify(mockCache, times(2)).getResourceManager(); + verify(mockResourceManager, times(1)).setCriticalHeapPercentage(eq(0.90f)); + verify(mockResourceManager, times(1)).setEvictionHeapPercentage(eq(0.75f)); + verify(mockCache, times(2)).getCacheTransactionManager(); + verify(mockCacheTransactionManager, times(1)).addListener(same(mockTransactionLister)); + verify(mockCacheTransactionManager, times(1)).setWriter(same(mockTransactionWriter)); + } + + @Test + public void testFetchExistingCache() throws Exception { + Cache mockCache = mock(Cache.class, "GemFireCache"); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + ReflectionUtils.setField(CacheFactoryBean.class.getDeclaredField("cache"), cacheFactoryBean, mockCache); + + Cache actualCache = cacheFactoryBean.resolveCache(); + + assertSame(mockCache, actualCache); + } + + @Test + public void testCreateWhenCacheExists() throws Exception { + Cache mockCache = mock(Cache.class, "GemFireCache"); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + ReflectionUtils.setField(CacheFactoryBean.class.getDeclaredField("cache"), cacheFactoryBean, mockCache); + + GemFireCache actualCache = cacheFactoryBean.createCache(null); + + assertSame(mockCache, actualCache); + } + + @Test(expected = IllegalArgumentException.class) + public void testPostProcessCacheWithInvalidCriticalHeapPercentage() throws Exception { + try { + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + cacheFactoryBean.setCriticalHeapPercentage(200.0f); + cacheFactoryBean.postProcess(null); + } + catch (IllegalArgumentException expected) { + assertEquals("'criticalHeapPercentage' (200.0) is invalid; must be > 0.0 and <= 100.0", + expected.getMessage()); + throw expected; + } + } + + @Test(expected = IllegalArgumentException.class) + public void testPostProcessCacheWithInvalidEvictionHeapPercentage() throws Exception { + try { + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + cacheFactoryBean.setEvictionHeapPercentage(-75.0f); + cacheFactoryBean.postProcess(null); + } + catch (IllegalArgumentException expected) { + assertEquals("'evictionHeapPercentage' (-75.0) is invalid; must be > 0.0 and <= 100.0", + expected.getMessage()); + throw expected; + } + } + + @Test + public void testPostProcessPropertiesBeforeInitializationDefaults() { + assumeTrue(GemfireUtils.isGemfireVersion8OrAbove()); + + Properties gemfireProperties = new Properties(); + + assertTrue(gemfireProperties.isEmpty()); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + cacheFactoryBean.postProcessPropertiesBeforeInitialization(gemfireProperties); + + assertEquals(2, gemfireProperties.size()); + assertTrue(gemfireProperties.containsKey("disable-auto-reconnect")); + assertTrue(gemfireProperties.containsKey("use-cluster-configuration")); + assertEquals("true", gemfireProperties.getProperty("disable-auto-reconnect")); + assertEquals("false", gemfireProperties.getProperty("use-cluster-configuration")); + } + + @Test + public void testPostProcessPropertiesBeforeInitializationDisabled() { + assumeTrue(GemfireUtils.isGemfireVersion8OrAbove()); + + Properties gemfireProperties = new Properties(); + + assertTrue(gemfireProperties.isEmpty()); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + cacheFactoryBean.setEnableAutoReconnect(false); + cacheFactoryBean.setUseClusterConfiguration(false); + cacheFactoryBean.postProcessPropertiesBeforeInitialization(gemfireProperties); + + assertEquals(2, gemfireProperties.size()); + assertTrue(gemfireProperties.containsKey("disable-auto-reconnect")); + assertTrue(gemfireProperties.containsKey("use-cluster-configuration")); + assertEquals("true", gemfireProperties.getProperty("disable-auto-reconnect")); + assertEquals("false", gemfireProperties.getProperty("use-cluster-configuration")); + } + + @Test + public void testPostProcessPropertiesBeforeInitializationEnabled() { + assumeTrue(GemfireUtils.isGemfireVersion8OrAbove()); + + Properties gemfireProperties = new Properties(); + + assertTrue(gemfireProperties.isEmpty()); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + cacheFactoryBean.setEnableAutoReconnect(true); + cacheFactoryBean.setUseClusterConfiguration(true); + cacheFactoryBean.postProcessPropertiesBeforeInitialization(gemfireProperties); + + assertEquals(2, gemfireProperties.size()); + assertTrue(gemfireProperties.containsKey("disable-auto-reconnect")); + assertTrue(gemfireProperties.containsKey("use-cluster-configuration")); + assertEquals("false", gemfireProperties.getProperty("disable-auto-reconnect")); + assertEquals("true", gemfireProperties.getProperty("use-cluster-configuration")); + } + + @Test + public void testGetObject() throws Exception { + final ClassLoader expectedThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); + final Cache mockCache = mock(Cache.class, "GemFireCache"); + + DistributedMember mockDistributedMember = mock(DistributedMember.class, "GemFireDistributedMember"); + DistributedSystem mockDistributedSystem = mock(DistributedSystem.class, "GemFireDistributedSystem"); + + when(mockCache.getDistributedSystem()).thenReturn(mockDistributedSystem); + when(mockDistributedSystem.getDistributedMember()).thenReturn(mockDistributedMember); + when(mockDistributedSystem.getName()).thenReturn("MockDistributedSystem"); + when(mockDistributedMember.getId()).thenReturn("MockDistributedMember"); + when(mockDistributedMember.getGroups()).thenReturn(Collections.emptyList()); + when(mockDistributedMember.getRoles()).thenReturn(Collections.emptySet()); + when(mockDistributedMember.getHost()).thenReturn("skullbox"); + when(mockDistributedMember.getProcessId()).thenReturn(67890); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() { + @Override protected GemFireCache fetchCache() { + assertSame(ClassLoader.getSystemClassLoader(), getBeanClassLoader()); + return mockCache; + } + }; + + cacheFactoryBean.setBeanClassLoader(ClassLoader.getSystemClassLoader()); + cacheFactoryBean.setBeanName("MockGemFireCache"); + cacheFactoryBean.setCopyOnRead(true); + cacheFactoryBean.setLockTimeout(5000); + cacheFactoryBean.setSearchTimeout(15000); + cacheFactoryBean.setUseBeanFactoryLocator(false); + + Cache actualCache = cacheFactoryBean.getObject(); + + assertSame(mockCache, actualCache); + assertSame(expectedThreadContextClassLoader, Thread.currentThread().getContextClassLoader()); + + verify(mockCache, times(1)).setCopyOnRead(eq(true)); + verify(mockCache, times(1)).setLockTimeout(eq(5000)); + verify(mockCache, times(1)).setSearchTimeout(eq(15000)); + verify(mockCache, never()).getCacheTransactionManager(); + verify(mockCache, never()).getResourceManager(); + verify(mockCache, never()).loadCacheXml(any(InputStream.class)); + verify(mockCache, never()).setGatewayConflictResolver(any(GatewayConflictResolver.class)); + verify(mockCache, never()).setLockLease(anyInt()); + verify(mockCache, never()).setMessageSyncInterval(anyInt()); + } + + @Test + public void testGetObjectType() { + assertEquals(Cache.class, new CacheFactoryBean().getObjectType()); + } + + @Test + public void testIsSingleton() { + assertTrue(new CacheFactoryBean().isSingleton()); + } + + @Test + public void testNullSafeCollectionWithNonNullCollection() { + assertNotNull(new CacheFactoryBean().nullSafeCollection(Collections.emptyList())); + } + + @Test + public void testNullSafeCollectionWithNullCollection() { + Collection collection = new CacheFactoryBean().nullSafeCollection(null); + + assertNotNull(collection); + assertTrue(collection.isEmpty()); + } + + @Test + public void testDestroy() throws Exception { + final Cache mockCache = mock(Cache.class, "GemFireCache"); + + GemfireBeanFactoryLocator mockGemfireBeanFactoryLocator = mock(GemfireBeanFactoryLocator.class); + + when(mockCache.isClosed()).thenReturn(false); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() { + @Override protected GemFireCache fetchCache() { + return mockCache; + } + }; + + ReflectionUtils.setField(CacheFactoryBean.class.getDeclaredField("beanFactoryLocator"), cacheFactoryBean, + mockGemfireBeanFactoryLocator); + + cacheFactoryBean.setClose(true); + cacheFactoryBean.setUseBeanFactoryLocator(true); + cacheFactoryBean.destroy(); + + verify(mockCache, times(1)).isClosed(); + verify(mockCache, times(1)).close(); + verify(mockGemfireBeanFactoryLocator, times(1)).destroy(); + } + + @Test + public void testDestroyWhenCacheIsNull() throws Exception { + final AtomicBoolean fetchCacheCalled = new AtomicBoolean(false); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() { + @Override protected GemFireCache fetchCache() { + fetchCacheCalled.set(true); + return null; + } + }; + + cacheFactoryBean.setClose(true); + cacheFactoryBean.setUseBeanFactoryLocator(true); + cacheFactoryBean.destroy(); + + assertTrue(fetchCacheCalled.get()); + } + + @Test + public void testDestroyWhenClosedIsFalse() throws Exception { + final AtomicBoolean fetchCacheCalled = new AtomicBoolean(false); + final Cache mockCache = mock(Cache.class, "GemFireCache"); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() { + @Override protected GemFireCache fetchCache() { + fetchCacheCalled.set(true); + return mockCache; + } + }; + + cacheFactoryBean.setClose(false); + cacheFactoryBean.setUseBeanFactoryLocator(false); + cacheFactoryBean.destroy(); + + verify(mockCache, never()).isClosed(); + verify(mockCache, never()).close(); + + assertFalse(fetchCacheCalled.get()); + } + + @Test + public void testSetAndGetCacheFactoryBeanProperties() throws Exception { + BeanFactory mockBeanFactory = mock(BeanFactory.class, "SpringBeanFactory"); + GatewayConflictResolver mockGatewayConflictResolver = mock(GatewayConflictResolver.class, "GemFireGatewayConflictResolver"); + PdxSerializer mockPdxSerializer = mock(PdxSerializer.class, "GemFirePdxSerializer"); + Resource mockCacheXml = mock(Resource.class, "GemFireCacheXml"); + TransactionListener mockTransactionListener = mock(TransactionListener.class, "GemFireTransactionListener"); + TransactionWriter mockTransactionWriter = mock(TransactionWriter.class, "GemFireTransactionWriter"); + + Properties gemfireProperties = new Properties(); + + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + cacheFactoryBean.setBeanClassLoader(Thread.currentThread().getContextClassLoader()); + cacheFactoryBean.setBeanFactory(mockBeanFactory); + cacheFactoryBean.setBeanName("TestCache"); + cacheFactoryBean.setCacheXml(mockCacheXml); + cacheFactoryBean.setProperties(gemfireProperties); + cacheFactoryBean.setLazyInitialize(false); + cacheFactoryBean.setUseBeanFactoryLocator(false); + cacheFactoryBean.setClose(false); + cacheFactoryBean.setCopyOnRead(true); + cacheFactoryBean.setDynamicRegionSupport(new CacheFactoryBean.DynamicRegionSupport()); + cacheFactoryBean.setEnableAutoReconnect(true); + cacheFactoryBean.setCriticalHeapPercentage(0.95f); + cacheFactoryBean.setEvictionHeapPercentage(0.70f); + cacheFactoryBean.setGatewayConflictResolver(mockGatewayConflictResolver); + cacheFactoryBean.setJndiDataSources(Collections.singletonList(new CacheFactoryBean.JndiDataSource())); + cacheFactoryBean.setLockLease(15000); + cacheFactoryBean.setLockTimeout(5000); + cacheFactoryBean.setMessageSyncInterval(10000); + cacheFactoryBean.setPdxSerializer(mockPdxSerializer); + cacheFactoryBean.setPdxReadSerialized(false); + cacheFactoryBean.setPdxPersistent(true); + cacheFactoryBean.setPdxIgnoreUnreadFields(true); + cacheFactoryBean.setPdxDiskStoreName("TestPdxDiskStore"); + cacheFactoryBean.setSearchTimeout(30000); + cacheFactoryBean.setTransactionListeners(Collections.singletonList(mockTransactionListener)); + cacheFactoryBean.setTransactionWriter(mockTransactionWriter); + cacheFactoryBean.setUseClusterConfiguration(true); + + assertEquals(Thread.currentThread().getContextClassLoader(), cacheFactoryBean.getBeanClassLoader()); + assertSame(mockBeanFactory, cacheFactoryBean.getBeanFactory()); + assertNull(cacheFactoryBean.getBeanFactoryLocator()); + assertEquals("TestCache", cacheFactoryBean.getBeanName()); + assertSame(mockCacheXml, cacheFactoryBean.getCacheXml()); + assertSame(gemfireProperties, cacheFactoryBean.getProperties()); + assertFalse(cacheFactoryBean.isLazyInitialize()); + assertTrue(Boolean.FALSE.equals(TestUtils.readField("useBeanFactoryLocator", cacheFactoryBean))); + assertTrue(Boolean.FALSE.equals(TestUtils.readField("close", cacheFactoryBean))); + assertTrue(cacheFactoryBean.getCopyOnRead()); + assertEquals(0.95f, cacheFactoryBean.getCriticalHeapPercentage().floatValue(), 0.0f); + assertNotNull(cacheFactoryBean.getDynamicRegionSupport()); + assertTrue(cacheFactoryBean.getEnableAutoReconnect()); + assertEquals(0.70f, cacheFactoryBean.getEvictionHeapPercentage().floatValue(), 0.0f); + assertSame(mockGatewayConflictResolver, cacheFactoryBean.getGatewayConflictResolver()); + assertNotNull(cacheFactoryBean.getJndiDataSources()); + assertEquals(1, cacheFactoryBean.getJndiDataSources().size()); + assertEquals(15000, cacheFactoryBean.getLockLease().intValue()); + assertEquals(5000, cacheFactoryBean.getLockTimeout().intValue()); + assertEquals(10000, cacheFactoryBean.getMessageSyncInterval().intValue()); + assertSame(mockPdxSerializer, cacheFactoryBean.getPdxSerializer()); + assertFalse(cacheFactoryBean.getPdxReadSerialized()); + assertTrue(cacheFactoryBean.getPdxPersistent()); + assertTrue(cacheFactoryBean.getPdxIgnoreUnreadFields()); + assertEquals("TestPdxDiskStore", cacheFactoryBean.getPdxDiskStoreName()); + assertEquals(30000, cacheFactoryBean.getSearchTimeout().intValue()); + assertNotNull(cacheFactoryBean.getTransactionListeners()); + assertEquals(1, cacheFactoryBean.getTransactionListeners().size()); + assertSame(mockTransactionListener, cacheFactoryBean.getTransactionListeners().get(0)); + assertSame(mockTransactionWriter, cacheFactoryBean.getTransactionWriter()); + assertTrue(cacheFactoryBean.getUseClusterConfiguration()); + } + +}