SGF-441 - Fix possible CacheClosedException in ClientCacheFactoryBean onApplicationEvent(:ContextRefreshedEvent) when the ClientCache initialization is lazy.

(cherry picked from commit f645e7d1a4ea1954c21aa2416b46669d97f4e18d)

Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
John Blum
2015-10-17 23:17:31 -07:00
parent 8cc93f72a0
commit a6b1189db6
12 changed files with 207 additions and 39 deletions

View File

@@ -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

View File

@@ -681,9 +681,21 @@ public class ClientCacheFactoryBeanTest {
verify(mockClientCache, never()).getDistributedSystem();
}
@Test
public void isReadyForEventsIsFalseWhenClientCacheNotInitialized() {
ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean() {
@Override protected <T extends GemFireCache> 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() {

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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));

View File

@@ -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());

View File

@@ -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));
}
}