diff --git a/src/main/java/org/springframework/data/gemfire/GemfireUtils.java b/src/main/java/org/springframework/data/gemfire/GemfireUtils.java index 20c9097a..12c4649e 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireUtils.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireUtils.java @@ -23,6 +23,8 @@ import org.springframework.data.gemfire.util.DistributedSystemUtils; import org.springframework.util.ClassUtils; import org.w3c.dom.Element; +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.CacheClosedException; import com.gemstone.gemfire.cache.CacheFactory; import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.client.ClientCache; @@ -37,6 +39,12 @@ import com.gemstone.gemfire.management.internal.cli.util.spring.StringUtils; * * @author John Blum * @see org.springframework.data.gemfire.util.DistributedSystemUtils + * @see com.gemstone.gemfire.cache.Cache + * @see com.gemstone.gemfire.cache.CacheFactory + * @see com.gemstone.gemfire.cache.Region + * @see com.gemstone.gemfire.cache.client.ClientCache + * @see com.gemstone.gemfire.cache.client.ClientCacheFactory + * @see com.gemstone.gemfire.distributed.DistributedSystem * @since 1.3.3 */ @SuppressWarnings("unused") @@ -102,7 +110,7 @@ public abstract class GemfireUtils extends DistributedSystemUtils { } public static boolean isDurable(ClientCache clientCache) { - DistributedSystem distributedSystem = clientCache.getDistributedSystem(); + DistributedSystem distributedSystem = getDistributedSystem(clientCache); // NOTE technically the following code snippet would be more useful/valuable but is not "testable"! //((InternalDistributedSystem) distributedSystem).getConfig().getDurableClientId(); @@ -131,14 +139,32 @@ public abstract class GemfireUtils extends DistributedSystemUtils { } } - public static boolean isGemfireVersionGreaterThanEqual(double expectedVersion) { + public static Cache getCache() { + try { + return CacheFactory.getAnyInstance(); + } + catch (CacheClosedException ignore) { + return null; + } + } + + public static ClientCache getClientCache() { + try { + return ClientCacheFactory.getAnyInstance(); + } + catch (CacheClosedException ignore) { + return null; + } + } + + public static boolean isGemfireVersionGreaterThanEqualTo(double expectedVersion) { double actualVersion = Double.parseDouble(GEMFIRE_VERSION.substring(0, 3)); return (actualVersion >= expectedVersion); } public static boolean isGemfireVersion65OrAbove() { try { - return isGemfireVersionGreaterThanEqual(6.5); + return isGemfireVersionGreaterThanEqualTo(6.5); } catch (NumberFormatException e) { // NOTE based on logic from the PartitionedRegionFactoryBean class... @@ -148,7 +174,7 @@ public abstract class GemfireUtils extends DistributedSystemUtils { public static boolean isGemfireVersion7OrAbove() { try { - return isGemfireVersionGreaterThanEqual(7.0); + return isGemfireVersionGreaterThanEqualTo(7.0); } catch (NumberFormatException e) { // NOTE the com.gemstone.gemfire.distributed.ServerLauncher class only exists in GemFire v 7.0.x or above... @@ -159,7 +185,7 @@ public abstract class GemfireUtils extends DistributedSystemUtils { public static boolean isGemfireVersion8OrAbove() { try { - return isGemfireVersionGreaterThanEqual(8.0); + return isGemfireVersionGreaterThanEqualTo(8.0); } catch (NumberFormatException e) { // NOTE the com.gemstone.gemfire.management.internal.web.domain.LinkIndex class only exists diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java index 2257151e..61fdb956 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java @@ -394,7 +394,12 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat return Boolean.TRUE.equals(readyForEvents); } else { - return GemfireUtils.isDurable((ClientCache) fetchCache()); + try { + return GemfireUtils.isDurable((ClientCache) fetchCache()); + } + catch (Throwable ignore) { + return false; + } } } diff --git a/src/main/java/org/springframework/data/gemfire/util/DistributedSystemUtils.java b/src/main/java/org/springframework/data/gemfire/util/DistributedSystemUtils.java index 27f10e00..140a12d9 100644 --- a/src/main/java/org/springframework/data/gemfire/util/DistributedSystemUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/DistributedSystemUtils.java @@ -20,6 +20,7 @@ import java.util.Properties; import org.springframework.util.Assert; +import com.gemstone.gemfire.cache.GemFireCache; import com.gemstone.gemfire.cache.server.CacheServer; import com.gemstone.gemfire.distributed.DistributedSystem; import com.gemstone.gemfire.distributed.internal.DistributionConfig; @@ -31,6 +32,7 @@ import com.gemstone.gemfire.management.internal.cli.util.spring.StringUtils; * DistributedSystemUtils is an abstract utility class for working with the GemFire DistributedSystem. * * @author John Blum + * @see com.gemstone.gemfire.cache.GemFireCache * @see com.gemstone.gemfire.distributed.DistributedSystem * @since 1.7.0 */ @@ -43,6 +45,7 @@ public abstract class DistributedSystemUtils { public static final String DURABLE_CLIENT_ID_PROPERTY_NAME = DistributionConfig.DURABLE_CLIENT_ID_NAME; public static final String DURABLE_CLIENT_TIMEOUT_PROPERTY_NAME = DistributionConfig.DURABLE_CLIENT_TIMEOUT_NAME; + /* (non-Javadoc) */ public static Properties configureDurableClient(Properties gemfireProperties, String durableClientId, Integer durableClientTimeout) { if (StringUtils.hasText(durableClientId)) { Assert.notNull(gemfireProperties, "gemfireProperties must not be null"); @@ -57,17 +60,26 @@ public abstract class DistributedSystemUtils { return gemfireProperties; } + /* (non-Javadoc) */ public static boolean isConnected(DistributedSystem distributedSystem) { return (distributedSystem != null && distributedSystem.isConnected()); } + /* (non-Javadoc) */ public static boolean isNotConnected(DistributedSystem distributedSystem) { return !isConnected(distributedSystem); } + /* (non-Javadoc) */ @SuppressWarnings("unchecked") public static T getDistributedSystem() { return (T) InternalDistributedSystem.getAnyInstance(); } + /* (non-Javadoc) */ + @SuppressWarnings("unchecked") + public static T getDistributedSystem(GemFireCache gemfireCache) { + return (gemfireCache != null ? (T) gemfireCache.getDistributedSystem() : null); + } + } diff --git a/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java b/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java index c67e7834..0af6f2ac 100644 --- a/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java +++ b/src/test/java/org/springframework/data/gemfire/GemfireTemplateTest.java @@ -38,6 +38,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.gemfire.test.AbstractMockerySupport; import org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -66,13 +67,14 @@ import com.gemstone.gemfire.cache.query.TypeMismatchException; * @see org.junit.Test * @see org.junit.runner.RunWith * @see org.springframework.data.gemfire.GemfireTemplate + * @see org.springframework.data.gemfire.test.AbstractMockerySupport * @see org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer * @see org.springframework.test.context.ContextConfiguration */ @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations="basic-template.xml", initializers=GemfireTestApplicationContextInitializer.class) +@ContextConfiguration(locations = "basic-template.xml", initializers = GemfireTestApplicationContextInitializer.class) @SuppressWarnings("unused") -public class GemfireTemplateTest { +public class GemfireTemplateTest extends AbstractMockerySupport { private static final String MULTI_QUERY = "SELECT * FROM /simple"; private static final String SINGLE_QUERY = "(SELECT * FROM /simple).size"; @@ -86,17 +88,19 @@ public class GemfireTemplateTest { @Before @SuppressWarnings("rawtypes") public void setUp() throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException { - QueryService queryService = simple.getRegionService().getQueryService(); - Query singleQuery = mock(Query.class); + if (isMocking()) { + QueryService queryService = simple.getRegionService().getQueryService(); + Query singleQuery = mock(Query.class); - when(singleQuery.execute(any(Object[].class))).thenReturn(0); - when(queryService.newQuery(SINGLE_QUERY)).thenReturn(singleQuery); + when(singleQuery.execute(any(Object[].class))).thenReturn(0); + when(queryService.newQuery(SINGLE_QUERY)).thenReturn(singleQuery); - Query multipleQuery = mock(Query.class); - SelectResults selectResults = mock(SelectResults.class); + Query multipleQuery = mock(Query.class); + SelectResults selectResults = mock(SelectResults.class); - when(multipleQuery.execute(any(Object[].class))).thenReturn(selectResults); - when(queryService.newQuery(MULTI_QUERY)).thenReturn(multipleQuery); + when(multipleQuery.execute(any(Object[].class))).thenReturn(selectResults); + when(queryService.newQuery(MULTI_QUERY)).thenReturn(multipleQuery); + } } @After diff --git a/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java index ef1b938b..5f2d579b 100644 --- a/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java +++ b/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java @@ -681,9 +681,21 @@ public class ClientCacheFactoryBeanTest { verify(mockClientCache, never()).getDistributedSystem(); } + @Test + public void isReadyForEventsIsFalseWhenClientCacheNotInitialized() { + ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean() { + @Override protected T fetchCache() { + throw new CacheClosedException("test"); + } + }; + + assertThat(clientCacheFactoryBean.getReadyForEvents(), is(nullValue())); + assertThat(clientCacheFactoryBean.isReadyForEvents(), is(false)); + } + @Test @SuppressWarnings("unchecked") - public void isReadyForEventsIsTrueWhenDurableClientIdSet() { + public void isReadyForEventsIsTrueWhenDurableClientIdIsSet() { final ClientCache mockClientCache = mockClientCache("TestDurableClientId"); ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean() { diff --git a/src/test/java/org/springframework/data/gemfire/client/LazyInitializedClientCacheIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/client/LazyInitializedClientCacheIntegrationTest.java new file mode 100644 index 00000000..868eeb27 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/client/LazyInitializedClientCacheIntegrationTest.java @@ -0,0 +1,92 @@ +/* + * 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.client; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.util.Properties; +import javax.annotation.Resource; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * The LazyInitializedClientCacheIntegrationTest class is a test suite of test cases testing the proper behavior a + * lazy initialized ClientCache by the SDG ClientCacheFactoryBean when the ClientCache instance is "looked up" + * in fetchCache() to ascertain whether the client is durable and readyForEvents needs to be signaled or not. + * + * @author John Blum + * @see org.junit.Test + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.annotation.Configuration + * @see org.springframework.data.gemfire.client.ClientCacheFactoryBean + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner + * @see com.gemstone.gemfire.cache.client.ClientCache + * @link https://jira.spring.io/browse/SGF-441 + * @since 1.0.0 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = LazyInitializedClientCacheIntegrationTest.GemFireConfiguration.class) +@SuppressWarnings("unused") +public class LazyInitializedClientCacheIntegrationTest { + + @Resource(name = "&clientCache") + private ClientCacheFactoryBean clientCacheFactoryBean; + + @Autowired + private Properties gemfireProperties; + + @Test + public void clientCacheFactoryBeanConfiguration() { + assertThat(clientCacheFactoryBean, is(notNullValue())); + assertThat(clientCacheFactoryBean.getBeanName(), is(equalTo("clientCache"))); + assertThat(clientCacheFactoryBean.isLazyInitialize(), is(equalTo(true))); + assertThat(clientCacheFactoryBean.getProperties(), is(equalTo(gemfireProperties))); + } + + @Configuration + public static class GemFireConfiguration { + + @Bean + public Properties gemfireProperties() { + Properties gemfireProperties = new Properties(); + gemfireProperties.setProperty("name", LazyInitializedClientCacheIntegrationTest.class.getSimpleName()); + gemfireProperties.setProperty("mcast-port", "0"); + gemfireProperties.setProperty("log-level", "warning"); + return gemfireProperties; + } + + @Bean + public ClientCacheFactoryBean clientCache() { + ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); + clientCacheFactoryBean.setUseBeanFactoryLocator(false); + clientCacheFactoryBean.setProperties(gemfireProperties()); + clientCacheFactoryBean.setLazyInitialize(true); + return clientCacheFactoryBean; + } + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/config/CacheNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/CacheNamespaceTest.java index a5a9e148..2fb4923a 100644 --- a/src/test/java/org/springframework/data/gemfire/config/CacheNamespaceTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/CacheNamespaceTest.java @@ -179,9 +179,9 @@ public class CacheNamespaceTest{ @Test(expected = IllegalArgumentException.class) public void testNoBeanFactoryLocator() throws Exception { - assertTrue(context.containsBean("no-bean-factory-locator")); + assertTrue(context.containsBean("no-bean-factory-locator-cache")); - CacheFactoryBean cacheFactoryBean = context.getBean("&no-bean-factory-locator", CacheFactoryBean.class); + CacheFactoryBean cacheFactoryBean = context.getBean("&no-bean-factory-locator-cache", CacheFactoryBean.class); assertThat(ReflectionTestUtils.getField(cacheFactoryBean, "beanFactoryLocator"), is(nullValue())); @@ -189,7 +189,7 @@ public class CacheNamespaceTest{ try { assertNotNull(beanFactoryLocator.useBeanFactory("cache-with-name")); - beanFactoryLocator.useBeanFactory("no-bean-factory-locator"); + beanFactoryLocator.useBeanFactory("no-bean-factory-locator-cache"); } finally { beanFactoryLocator.destroy(); @@ -197,7 +197,7 @@ public class CacheNamespaceTest{ } @Test - public void testNamedClientCache() throws Exception { + public void namedClientCacheWithNoProperties() throws Exception { assertTrue(context.containsBean("client-cache-with-name")); ClientCacheFactoryBean clientCacheFactoryBean = context.getBean("&client-cache-with-name", ClientCacheFactoryBean.class); @@ -211,7 +211,7 @@ public class CacheNamespaceTest{ } @Test - public void testClientCacheWithXml() throws Exception { + public void clientCacheWithXmlNoProperties() throws Exception { assertTrue(context.containsBean("client-cache-with-xml")); ClientCacheFactoryBean clientCacheFactoryBean = context.getBean("&client-cache-with-xml", ClientCacheFactoryBean.class); diff --git a/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java index d5fe1420..c52c6f82 100644 --- a/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/PoolNamespaceTest.java @@ -46,7 +46,7 @@ import com.gemstone.gemfire.cache.client.PoolManager; * @author John Blum */ @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations="pool-ns.xml", initializers=GemfireTestApplicationContextInitializer.class) +@ContextConfiguration(locations = "pool-ns.xml", initializers = GemfireTestApplicationContextInitializer.class) @SuppressWarnings("unused") public class PoolNamespaceTest { @@ -117,10 +117,10 @@ public class PoolNamespaceTest { } @Test - public void testComplexPool() throws Exception { - assertTrue(context.containsBean("complex")); + public void testServerPool() throws Exception { + assertTrue(context.containsBean("server")); - PoolFactoryBean poolFactoryBean = context.getBean("&complex", PoolFactoryBean.class); + PoolFactoryBean poolFactoryBean = context.getBean("&server", PoolFactoryBean.class); assertEquals(2000, TestUtils.readField("freeConnectionTimeout", poolFactoryBean)); assertEquals(20000l, TestUtils.readField("idleTimeout", poolFactoryBean)); diff --git a/src/test/java/org/springframework/data/gemfire/test/AbstractMockerySupport.java b/src/test/java/org/springframework/data/gemfire/test/AbstractMockerySupport.java index 4b0c9d58..9c8eb9c2 100644 --- a/src/test/java/org/springframework/data/gemfire/test/AbstractMockerySupport.java +++ b/src/test/java/org/springframework/data/gemfire/test/AbstractMockerySupport.java @@ -19,6 +19,8 @@ package org.springframework.data.gemfire.test; import org.springframework.data.gemfire.test.support.IdentifierSequence; import org.springframework.data.gemfire.test.support.StackTraceUtils; +import com.gemstone.gemfire.management.internal.cli.util.spring.StringUtils; + /** * The AbstractMockery class is an abstract base class supporting the creation and use of mock objects in unit tests. * @@ -30,6 +32,19 @@ public abstract class AbstractMockerySupport { protected static final String NOT_IMPLEMENTED = "Not Implemented"; + protected boolean isMocking() { + String gemfireTestRunnerNoMock = StringUtils.trimWhitespace(System.getProperty( + GemfireTestApplicationContextInitializer.GEMFIRE_TEST_RUNNER_DISABLED, "false")); + + return !(Boolean.parseBoolean(gemfireTestRunnerNoMock) + || "yes".equalsIgnoreCase(gemfireTestRunnerNoMock) + || "y".equalsIgnoreCase(gemfireTestRunnerNoMock)); + } + + protected boolean isNotMocking() { + return !isMocking(); + } + protected Object getMockId() { StackTraceElement element = StackTraceUtils.getTestCaller(); return (element != null ? StackTraceUtils.getCallerSimpleName(element): IdentifierSequence.nextId()); diff --git a/src/test/java/org/springframework/data/gemfire/test/GemfireTestApplicationContextInitializer.java b/src/test/java/org/springframework/data/gemfire/test/GemfireTestApplicationContextInitializer.java index 1e148fa7..fedf64ab 100644 --- a/src/test/java/org/springframework/data/gemfire/test/GemfireTestApplicationContextInitializer.java +++ b/src/test/java/org/springframework/data/gemfire/test/GemfireTestApplicationContextInitializer.java @@ -48,7 +48,8 @@ public class GemfireTestApplicationContextInitializer implements ApplicationCont private boolean isGemFireTestRunnerDisable(final String systemPropertyValue) { return (Boolean.valueOf(StringUtils.trimAllWhitespace(systemPropertyValue)) - || "yes".equalsIgnoreCase(systemPropertyValue)); + || "yes".equalsIgnoreCase(systemPropertyValue) + || "y".equalsIgnoreCase(systemPropertyValue)); } } diff --git a/src/test/resources/org/springframework/data/gemfire/config/cache-ns.xml b/src/test/resources/org/springframework/data/gemfire/config/cache-ns.xml index ba309a7a..9af8a595 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/cache-ns.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/cache-ns.xml @@ -12,24 +12,25 @@ + + false + warning + + - - false - - - + - + - + - + diff --git a/src/test/resources/org/springframework/data/gemfire/config/pool-ns.xml b/src/test/resources/org/springframework/data/gemfire/config/pool-ns.xml index ca890f21..8c374f87 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/pool-ns.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/pool-ns.xml @@ -11,16 +11,16 @@ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd "> + + PoolNamespaceConfig 0 - error + warning - - @@ -29,7 +29,7 @@ -