/* * 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.config.xml; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.File; import java.io.FilenameFilter; import java.util.concurrent.atomic.AtomicReference; import org.apache.geode.cache.CacheListener; import org.apache.geode.cache.CacheLoader; import org.apache.geode.cache.CacheLoaderException; import org.apache.geode.cache.DataPolicy; import org.apache.geode.cache.EvictionAction; import org.apache.geode.cache.EvictionAlgorithm; import org.apache.geode.cache.EvictionAttributes; import org.apache.geode.cache.ExpirationAction; import org.apache.geode.cache.InterestResultPolicy; import org.apache.geode.cache.LoaderHelper; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.client.ClientCache; import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.util.CacheWriterAdapter; import org.apache.geode.compression.Compressor; import org.junit.AfterClass; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.data.gemfire.SimpleCacheListener; import org.springframework.data.gemfire.SimpleObjectSizer; import org.springframework.data.gemfire.TestUtils; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; import org.springframework.data.gemfire.client.Interest; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.ObjectUtils; /** * The ClientRegionNamespaceTest class is a test suite of test cases testing the contract and functionality * of GemFire Client Region namespace support in SDG. * * @author Costin Leau * @author David Turanski * @author John Blum * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean * @see org.springframework.data.gemfire.config.xml.ClientRegionParser */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="client-ns.xml") @SuppressWarnings("unused") public class ClientRegionNamespaceTest { @Autowired private ApplicationContext context; @AfterClass public static void tearDown() { for (String name : new File(".").list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.startsWith("BACKUP"); } })) { new File(name).delete(); } } @Test public void testBeanNames() throws Exception { assertTrue(context.containsBean("SimpleRegion")); assertTrue(context.containsBean("Publisher")); assertTrue(context.containsBean("ComplexRegion")); assertTrue(context.containsBean("PersistentRegion")); assertTrue(context.containsBean("OverflowRegion")); assertTrue(context.containsBean("Compressed")); } @Test public void testSimpleClientRegion() throws Exception { assertTrue(context.containsBean("simple")); Region<?, ?> simple = context.getBean("simple", Region.class); assertNotNull("The 'SimpleRegion' Client Region was not properly configured and initialized!", simple); assertEquals("SimpleRegion", simple.getName()); assertEquals(Region.SEPARATOR + "SimpleRegion", simple.getFullPath()); assertNotNull(simple.getAttributes()); assertEquals(DataPolicy.NORMAL, simple.getAttributes().getDataPolicy()); } @Test @SuppressWarnings("rawtypes") public void testPublishingClientRegion() throws Exception { assertTrue(context.containsBean("empty")); ClientRegionFactoryBean emptyClientRegionFactoryBean = context.getBean("&empty", ClientRegionFactoryBean.class); assertNotNull(emptyClientRegionFactoryBean); assertEquals(DataPolicy.EMPTY, TestUtils.readField("dataPolicy", emptyClientRegionFactoryBean)); assertEquals("empty", TestUtils.readField("beanName", emptyClientRegionFactoryBean)); assertEquals("Publisher", TestUtils.readField("name", emptyClientRegionFactoryBean)); assertEquals("gemfire-pool", TestUtils.readField("poolName", emptyClientRegionFactoryBean)); } @Test @SuppressWarnings("rawtypes") public void testComplexClientRegion() throws Exception { assertTrue(context.containsBean("complex")); ClientRegionFactoryBean complexClientRegionFactoryBean = context.getBean("&complex", ClientRegionFactoryBean.class); assertNotNull(complexClientRegionFactoryBean); CacheListener[] cacheListeners = TestUtils.readField("cacheListeners", complexClientRegionFactoryBean); assertFalse(ObjectUtils.isEmpty(cacheListeners)); assertEquals(2, cacheListeners.length); assertSame(cacheListeners[0], context.getBean("c-listener")); assertTrue(cacheListeners[1] instanceof SimpleCacheListener); assertNotSame(cacheListeners[0], cacheListeners[1]); RegionAttributes complexRegionAttributes = TestUtils.readField("attributes", complexClientRegionFactoryBean); assertNotNull(complexRegionAttributes); assertEquals(0.5f, complexRegionAttributes.getLoadFactor(), 0.001); assertEquals(ExpirationAction.INVALIDATE, complexRegionAttributes.getEntryTimeToLive().getAction()); assertEquals(500, complexRegionAttributes.getEntryTimeToLive().getTimeout()); assertEquals(5, complexRegionAttributes.getEvictionAttributes().getMaximum()); } @Test @SuppressWarnings({ "deprecation", "rawtypes" }) public void testPersistentClientRegion() throws Exception { assertTrue(context.containsBean("persistent")); Region persistent = context.getBean("persistent", Region.class); assertNotNull("The 'PersistentRegion' Region was not properly configured and initialized!", persistent); assertEquals("PersistentRegion", persistent.getName()); assertEquals(Region.SEPARATOR + "PersistentRegion", persistent.getFullPath()); RegionAttributes persistentRegionAttributes = persistent.getAttributes(); assertEquals(DataPolicy.PERSISTENT_REPLICATE, persistentRegionAttributes.getDataPolicy()); assertEquals("diskStore", persistentRegionAttributes.getDiskStoreName()); assertEquals("gemfire-pool", persistentRegionAttributes.getPoolName()); } @Test @SuppressWarnings("rawtypes") public void testOverflowClientRegion() throws Exception { assertTrue(context.containsBean("overflow")); ClientRegionFactoryBean overflowClientRegionFactoryBean = context.getBean("&overflow", ClientRegionFactoryBean.class); assertNotNull(overflowClientRegionFactoryBean); assertEquals("diskStore", TestUtils.readField("diskStoreName", overflowClientRegionFactoryBean)); assertEquals("gemfire-pool", TestUtils.readField("poolName", overflowClientRegionFactoryBean)); RegionAttributes overflowRegionAttributes = TestUtils.readField("attributes", overflowClientRegionFactoryBean); assertNotNull(overflowRegionAttributes); assertEquals(DataPolicy.NORMAL, overflowRegionAttributes.getDataPolicy()); EvictionAttributes overflowEvictionAttributes = overflowRegionAttributes.getEvictionAttributes(); assertNotNull(overflowEvictionAttributes); assertEquals(EvictionAction.OVERFLOW_TO_DISK, overflowEvictionAttributes.getAction()); assertEquals(EvictionAlgorithm.LRU_MEMORY, overflowEvictionAttributes.getAlgorithm()); assertEquals(10, overflowEvictionAttributes.getMaximum()); assertTrue(overflowEvictionAttributes.getObjectSizer() instanceof SimpleObjectSizer); } @Test public void testClientRegionWithCacheLoaderAndCacheWriter() throws Exception { assertTrue(context.containsBean("loadWithWrite")); ClientRegionFactoryBean factory = context.getBean("&loadWithWrite", ClientRegionFactoryBean.class); assertNotNull(factory); assertEquals("LoadedFullOfWrites", TestUtils.readField("name", factory)); assertEquals(ClientRegionShortcut.LOCAL, TestUtils.readField("shortcut", factory)); assertTrue(TestUtils.readField("cacheLoader", factory) instanceof TestCacheLoader); assertTrue(TestUtils.readField("cacheWriter", factory) instanceof TestCacheWriter); } @Test public void testCompressedReplicateRegion() { assertTrue(context.containsBean("Compressed")); Region<?, ?> compressed = context.getBean("Compressed", Region.class); assertNotNull("The 'Compressed' Client Region was not properly configured and initialized!", compressed); assertEquals("Compressed", compressed.getName()); assertEquals(Region.SEPARATOR + "Compressed", compressed.getFullPath()); assertNotNull(compressed.getAttributes()); assertEquals(DataPolicy.EMPTY, compressed.getAttributes().getDataPolicy()); assertEquals("gemfire-pool", compressed.getAttributes().getPoolName()); assertTrue(String.format("Expected 'TestCompressor'; but was '%1$s'!", ObjectUtils.nullSafeClassName(compressed.getAttributes().getCompressor())), compressed.getAttributes().getCompressor() instanceof TestCompressor); assertEquals("STD", compressed.getAttributes().getCompressor().toString()); } @Test @SuppressWarnings("unchecked") public void testClientRegionWithAttributes() { assertTrue(context.containsBean("client-with-attributes")); Region<Long, String> clientRegion = context.getBean("client-with-attributes", Region.class); assertNotNull("The 'client-with-attributes' Client Region was not properly configured and initialized!", clientRegion); assertEquals("client-with-attributes", clientRegion.getName()); assertEquals(Region.SEPARATOR + "client-with-attributes", clientRegion.getFullPath()); assertNotNull(clientRegion.getAttributes()); assertFalse(clientRegion.getAttributes().getCloningEnabled()); assertTrue(clientRegion.getAttributes().getConcurrencyChecksEnabled()); assertEquals(8, clientRegion.getAttributes().getConcurrencyLevel()); assertEquals(DataPolicy.NORMAL, clientRegion.getAttributes().getDataPolicy()); assertFalse(clientRegion.getAttributes().getDataPolicy().withPersistence()); assertEquals(64, clientRegion.getAttributes().getInitialCapacity()); assertEquals(Long.class, clientRegion.getAttributes().getKeyConstraint()); assertEquals("0.85", String.valueOf(clientRegion.getAttributes().getLoadFactor())); assertEquals("gemfire-pool", clientRegion.getAttributes().getPoolName()); assertEquals(String.class, clientRegion.getAttributes().getValueConstraint()); } @Test @SuppressWarnings("unchecked") public void testClientRegionWithRegisteredInterests() throws Exception { assertTrue(context.containsBean("client-with-interests")); ClientRegionFactoryBean factoryBean = context.getBean("&client-with-interests", ClientRegionFactoryBean.class); assertNotNull(factoryBean); Interest<?>[] interests = TestUtils.readField("interests", factoryBean); assertNotNull(interests); assertEquals(2, interests.length); assertInterest(true, false, InterestResultPolicy.KEYS, getInterestWithKey(".*", interests)); assertInterest(true, false, InterestResultPolicy.KEYS_VALUES, getInterestWithKey("keyPrefix.*", interests)); Region mockClientRegion = MockCacheFactoryBean.MOCK_REGION_REF.get(); assertNotNull(mockClientRegion); verify(mockClientRegion, times(1)).registerInterest(eq(".*"), eq(InterestResultPolicy.KEYS), eq(true), eq(false)); verify(mockClientRegion, times(1)).registerInterestRegex(eq("keyPrefix.*"), eq(InterestResultPolicy.KEYS_VALUES), eq(true), eq(false)); } protected void assertInterest(final boolean expectedDurable, final boolean expectedReceiveValues, final InterestResultPolicy expectedPolicy, final Interest actualInterest) { assertNotNull(actualInterest); assertEquals(expectedDurable, actualInterest.isDurable()); assertEquals(expectedReceiveValues, actualInterest.isReceiveValues()); assertEquals(expectedPolicy, actualInterest.getPolicy()); } protected Interest getInterestWithKey(final String key, final Interest... interests) { for (Interest interest : interests) { if (interest.getKey().equals(key)) { return interest; } } return null; } public static final class MockCacheFactoryBean implements FactoryBean<ClientCache>, InitializingBean { protected static final AtomicReference<Region> MOCK_REGION_REF = new AtomicReference<Region>(null); private ClientCache mockClientCache; @Override @SuppressWarnings("unchecked") public void afterPropertiesSet() throws Exception { mockClientCache = mock(ClientCache.class, ClientRegionNamespaceTest.class.getSimpleName() .concat(".MockClientCache")); MOCK_REGION_REF.compareAndSet(null, mock(Region.class, ClientRegionNamespaceTest.class.getSimpleName() .concat(".MockClientRegion"))); when(mockClientCache.getRegion(anyString())).thenReturn(MOCK_REGION_REF.get()); } @Override public ClientCache getObject() throws Exception { return mockClientCache; } @Override public Class<?> getObjectType() { return ClientCache.class; } @Override public boolean isSingleton() { return true; } } public static final class TestCacheLoader implements CacheLoader<Object, Object> { @Override public Object load(final LoaderHelper<Object, Object> helper) throws CacheLoaderException { throw new UnsupportedOperationException("Not Implemented!"); } @Override public void close() { } } public static final class TestCacheWriter extends CacheWriterAdapter<Object, Object> { } public static class TestCompressor implements Compressor { private String name; public void setName(final String name) { this.name = name; } @Override public byte[] compress(final byte[] input) { throw new UnsupportedOperationException("Not Implemented!"); } @Override public byte[] decompress(final byte[] input) { throw new UnsupportedOperationException("Not Implemented!"); } @Override public String toString() { return this.name; } } }