diff --git a/src/main/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepository.java b/src/main/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepository.java index 6659fae8..e2c5ec23 100644 --- a/src/main/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepository.java +++ b/src/main/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepository.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.data.gemfire.repository.support; import java.io.Serializable; @@ -21,6 +22,8 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheTransactionManager; @@ -33,6 +36,7 @@ import org.springframework.data.gemfire.GemfireTemplate; import org.springframework.data.gemfire.repository.GemfireRepository; import org.springframework.data.gemfire.repository.Wrapper; import org.springframework.data.gemfire.repository.query.QueryString; +import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.data.repository.core.EntityInformation; import org.springframework.util.Assert; @@ -50,9 +54,10 @@ import org.springframework.util.Assert; */ public class SimpleGemfireRepository implements GemfireRepository { - private final GemfireTemplate template; private final EntityInformation entityInformation; + private final GemfireTemplate template; + /** * Creates a new {@link SimpleGemfireRepository}. * @@ -60,9 +65,8 @@ public class SimpleGemfireRepository implements Gemf * @param entityInformation must not be {@literal null}. */ public SimpleGemfireRepository(GemfireTemplate template, EntityInformation entityInformation) { - - Assert.notNull(template); - Assert.notNull(entityInformation); + Assert.notNull(template, "Template must not be null"); + Assert.notNull(entityInformation, "EntityInformation must not be null"); this.template = template; this.entityInformation = entityInformation; @@ -70,7 +74,6 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * * @see org.springframework.data.repository.CrudRepository#save(S) */ @Override @@ -81,12 +84,11 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * * @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable) */ @Override public Iterable save(Iterable entities) { - Map result = new HashMap(); + Map result = new HashMap<>(); for (U entity : entities) { result.put(entityInformation.getId(entity), entity); @@ -99,19 +101,17 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * - * @see - * org.springframework.data.gemfire.repository.GemfireRepository#save( - * org.springframework.data.gemfire.repository.Wrapper) + * @see org.springframework.data.gemfire.repository.GemfireRepository#save(org.springframework.data.gemfire.repository.Wrapper) */ @Override public T save(Wrapper wrapper) { - return template.put(wrapper.getKey(), wrapper.getEntity()); + T entity = wrapper.getEntity(); + template.put(wrapper.getKey(), entity); + return entity; } /* * (non-Javadoc) - * * @see org.springframework.data.repository.CrudRepository#count() */ @Override @@ -122,7 +122,6 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * * @see org.springframework.data.repository.CrudRepository#exists(java.io.Serializable) */ @Override @@ -132,7 +131,6 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * * @see org.springframework.data.repository.CrudRepository#findOne(java.io.Serializable) */ @Override @@ -143,7 +141,6 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * * @see org.springframework.data.repository.CrudRepository#findAll() */ @Override @@ -169,24 +166,23 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * * @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable) */ @Override @SuppressWarnings("unchecked") public Collection findAll(Iterable ids) { - List parameters = new ArrayList(); + List parameters = new ArrayList<>(); for (ID id : ids) { parameters.add(id); } - return (Collection) template.getAll(parameters).values(); + return CollectionUtils.nullSafeMap(template.getAll(parameters)).values().stream() + .filter(Objects::nonNull).collect(Collectors.toList()); } /* * (non-Javadoc) - * * @see org.springframework.data.repository.CrudRepository#delete(java.io.Serializable) */ @Override @@ -196,9 +192,7 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * - * @see - * org.springframework.data.repository.CrudRepository#delete(java.lang.Object) + * @see org.springframework.data.repository.CrudRepository#delete(java.lang.Object) */ @Override public void delete(T entity) { @@ -207,9 +201,7 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * - * @see - * org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable) + * @see org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable) */ @Override public void delete(Iterable entities) { @@ -220,76 +212,66 @@ public class SimpleGemfireRepository implements Gemf /* * (non-Javadoc) - * * @see org.apache.geode.cache.Region#getAttributes() * @see org.apache.geode.cache.RegionAttributes#getDataPolicy() */ - boolean isPartitioned(final Region region) { + boolean isPartitioned(Region region) { return (region != null && region.getAttributes() != null && isPartitioned(region.getAttributes().getDataPolicy())); } /* * (non-Javadoc) - * * @see org.apache.geode.cache.DataPolicy#withPartitioning() */ - boolean isPartitioned(final DataPolicy dataPolicy) { + boolean isPartitioned(DataPolicy dataPolicy) { return (dataPolicy != null && dataPolicy.withPartitioning()); } /* * (non-Javadoc) - * * @see org.apache.geode.cache.Region#getRegionService() * @see org.apache.geode.cache.Cache#getCacheTransactionManager() */ - boolean isTransactionPresent(final Region region) { + boolean isTransactionPresent(Region region) { return (region.getRegionService() instanceof Cache && isTransactionPresent(((Cache) region.getRegionService()).getCacheTransactionManager())); } /* * (non-Javadoc) - * * @see org.apache.geode.cache.CacheTransactionManager#exists() */ - boolean isTransactionPresent(final CacheTransactionManager cacheTransactionManager) { + boolean isTransactionPresent(CacheTransactionManager cacheTransactionManager) { return (cacheTransactionManager != null && cacheTransactionManager.exists()); } /* (non-Javadoc) */ @SuppressWarnings("unchecked") - void doRegionClear(final Region region) { + void doRegionClear(Region region) { region.removeAll(region.keySet()); } /* * (non-Javadoc) - * * @see org.springframework.data.repository.CrudRepository#deleteAll() */ @Override public void deleteAll() { - template.execute(new GemfireCallback() { - @Override - @SuppressWarnings("rawtypes") - public Void doInGemfire(final Region region) { - if (isPartitioned(region) || isTransactionPresent(region)) { + template.execute((GemfireCallback) region -> { + if (isPartitioned(region) || isTransactionPresent(region)) { + doRegionClear(region); + } + else { + try { + region.clear(); + } + catch (UnsupportedOperationException ignore) { doRegionClear(region); } - else { - try { - region.clear(); - } - catch (UnsupportedOperationException ignore) { - doRegionClear(region); - } - } - - return null; } + + return null; }); } - } diff --git a/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTests.java index 71ac8596..619dc23f 100644 --- a/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryIntegrationTests.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.data.gemfire.repository.support; import static org.assertj.core.api.Assertions.assertThat; @@ -20,7 +21,6 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Properties; import javax.annotation.Resource; @@ -34,15 +34,14 @@ 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.data.gemfire.CacheFactoryBean; import org.springframework.data.gemfire.GemfireTemplate; import org.springframework.data.gemfire.LocalRegionFactoryBean; +import org.springframework.data.gemfire.config.annotation.PeerCacheApplication; import org.springframework.data.gemfire.repository.sample.Person; import org.springframework.data.repository.core.EntityInformation; import org.springframework.data.repository.core.support.ReflectionEntityInformation; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit4.SpringRunner; /** * Integration tests for {@link SimpleGemfireRepository}. @@ -51,8 +50,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * @author John Blum * @see org.junit.Test * @see org.springframework.data.gemfire.repository.support.SimpleGemfireRepository + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner */ -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(SpringRunner.class) @ContextConfiguration @SuppressWarnings("unused") public class SimpleGemfireRepositoryIntegrationTests { @@ -75,8 +76,70 @@ public class SimpleGemfireRepositoryIntegrationTests { people.clear(); regionClearListener = new RegionClearListener(); people.getAttributesMutator().addCacheListener(regionClearListener); - EntityInformation information = new ReflectionEntityInformation(Person.class); - repository = new SimpleGemfireRepository(template, information); + EntityInformation information = new ReflectionEntityInformation<>(Person.class); + repository = new SimpleGemfireRepository<>(template, information); + } + + @Test + public void deleteAllFiresClearEvent() { + assertThat(regionClearListener.eventFired).isFalse(); + repository.deleteAll(); + assertThat(regionClearListener.eventFired).isTrue(); + } + + @Test + public void findAllWithIds() { + Person dave = new Person(1L, "Dave", "Matthews"); + Person carter = new Person(2L, "Carter", "Beauford"); + Person leroi = new Person(3L, "Leroi", "Moore"); + + template.put(dave.getId(), dave); + template.put(carter.getId(), carter); + template.put(leroi.getId(), leroi); + + Collection result = repository.findAll(Arrays.asList(carter.getId(), leroi.getId())); + + assertThat(result).isNotNull(); + assertThat(result.size()).isEqualTo(2); + assertThat(result).containsAll(Arrays.asList(carter, leroi)); + } + + @Test + public void findAllWithIdsReturnsNoMatches() { + Collection results = repository.findAll(Arrays.asList(1L, 2L)); + + assertThat(results).isNotNull(); + assertThat(results).isEmpty(); + } + + @Test + public void findAllWithIdsReturnsPartialMatches() { + Person kurt = new Person(1L, "Kurt", "Cobain"); + Person eddie = new Person(2L, "Eddie", "Veddar"); + Person michael = new Person(3L, "Michael", "Jackson"); + + template.put(kurt.getId(), kurt); + template.put(eddie.getId(), eddie); + + Collection results = repository.findAll(Arrays.asList(0L, 1L, 2L, 4L)); + + assertThat(results).isNotNull(); + assertThat(results).hasSize(2); + assertThat(results).contains(kurt, eddie); + assertThat(results).doesNotContain(michael); + } + + @Test + public void queryRegion() throws Exception { + Person oliverGierke = new Person(1L, "Oliver", "Gierke"); + + assertThat(template.put(oliverGierke.getId(), oliverGierke)).isNull(); + + SelectResults people = template.find("SELECT * FROM /People p WHERE p.firstname = $1", + oliverGierke.getFirstname()); + + assertThat(people.size()).isEqualTo(1); + assertThat(people.iterator().next()).isEqualTo(oliverGierke); } @Test @@ -95,50 +158,13 @@ public class SimpleGemfireRepositoryIntegrationTests { assertThat(repository.findAll()).isEmpty(); } - @Test - public void deleteAllFiresClearEvent() { - assertThat(regionClearListener.eventFired).isFalse(); - repository.deleteAll(); - assertThat(regionClearListener.eventFired).isTrue(); - } - - @Test - public void queryRegion() throws Exception { - Person oliverGierke = new Person(1L, "Oliver", "Gierke"); - - assertThat(template.put(oliverGierke.getId(), oliverGierke)).isNull(); - - SelectResults people = template.find("SELECT * FROM /People p WHERE p.firstname = $1", - oliverGierke.getFirstname()); - - assertThat(people.size()).isEqualTo(1); - assertThat(people.iterator().next()).isEqualTo(oliverGierke); - } - - @Test - public void findAllWithGivenIds() { - Person dave = new Person(1L, "Dave", "Matthews"); - Person carter = new Person(2L, "Carter", "Beauford"); - Person leroi = new Person(3L, "Leroi", "Moore"); - - template.put(dave.getId(), dave); - template.put(carter.getId(), carter); - template.put(leroi.getId(), leroi); - - Collection result = repository.findAll(Arrays.asList(carter.getId(), leroi.getId())); - - assertThat(result).isNotNull(); - assertThat(result.size()).isEqualTo(2); - assertThat(result).containsAll(Arrays.asList(carter, leroi)); - } - @Test public void saveEntities() { assertThat(template.getRegion()).isEmpty(); - Person johnBlum = new Person(1l, "John", "Blum"); - Person jonBloom = new Person(2l, "Jon", "Bloom"); - Person juanBlume = new Person(3l, "Juan", "Blume"); + Person johnBlum = new Person(1L, "John", "Blum"); + Person jonBloom = new Person(2L, "Jon", "Bloom"); + Person juanBlume = new Person(3L, "Juan", "Blume"); repository.save(Arrays.asList(johnBlum, jonBloom, juanBlume)); @@ -159,39 +185,12 @@ public class SimpleGemfireRepositoryIntegrationTests { } } - @Configuration + @PeerCacheApplication(name = "SimpleGemfireRepositoryIntegrationTests", logLevel = DEFAULT_GEMFIRE_LOG_LEVEL) static class SimpleGemfireRepositoryConfiguration { - Properties gemfireProperties() { - Properties gemfireProperties = new Properties(); - - gemfireProperties.setProperty("name", applicationName()); - gemfireProperties.setProperty("mcast-port", "0"); - gemfireProperties.setProperty("log-level", logLevel()); - return gemfireProperties; - } - - String applicationName() { - return SimpleGemfireRepositoryIntegrationTests.class.getName(); - } - - String logLevel() { - return System.getProperty("gemfire.log-level", DEFAULT_GEMFIRE_LOG_LEVEL); - } - - @Bean - CacheFactoryBean gemfireCache() { - CacheFactoryBean gemfireCache = new CacheFactoryBean(); - - gemfireCache.setClose(false); - gemfireCache.setProperties(gemfireProperties()); - - return gemfireCache; - } - @Bean(name = "People") LocalRegionFactoryBean peopleRegion(GemFireCache gemfireCache) { - LocalRegionFactoryBean peopleRegion = new LocalRegionFactoryBean(); + LocalRegionFactoryBean peopleRegion = new LocalRegionFactoryBean<>(); peopleRegion.setCache(gemfireCache); peopleRegion.setClose(false); diff --git a/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryUnitTest.java b/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryUnitTest.java deleted file mode 100644 index 538f8e31..00000000 --- a/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryUnitTest.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * 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.repository.support; - -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.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doThrow; -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.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicLong; - -import org.apache.geode.cache.Cache; -import org.apache.geode.cache.CacheTransactionManager; -import org.apache.geode.cache.DataPolicy; -import org.apache.geode.cache.Region; -import org.apache.geode.cache.RegionAttributes; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.springframework.data.gemfire.GemfireTemplate; -import org.springframework.data.gemfire.repository.Wrapper; -import org.springframework.data.gemfire.repository.sample.Animal; -import org.springframework.data.gemfire.util.CollectionUtils; -import org.springframework.data.repository.core.EntityInformation; - -/** - * The SimpleGemfireRepositoryUnitTest class is a test suite of test cases testing the contract and functionality - * of the SimpleGemfireRepository class. - * - * @author John Blum - * @see org.junit.Test - * @see org.mockito.Mockito - * @see org.springframework.data.gemfire.GemfireTemplate - * @see org.springframework.data.gemfire.repository.Wrapper - * @see org.springframework.data.gemfire.repository.support.SimpleGemfireRepository - * @since 1.4.5 - */ -@SuppressWarnings("unchecked") -public class SimpleGemfireRepositoryUnitTest { - - protected Map asMap(Iterable animals) { - Map animalMap = new HashMap(); - for (Animal animal : animals) { - animalMap.put(animal.getId(), animal); - } - return animalMap; - } - - protected Animal createAnimal(final String name) { - Animal animal = new Animal(); - animal.setName(name); - return animal; - } - - protected Animal createAnimal(final Long id, final String name) { - Animal animal = createAnimal(name); - animal.setId(id); - return animal; - } - - protected GemfireTemplate createGemfireTemplate(final Region region) { - return new GemfireTemplate(region); - } - - protected Cache mockCache(final String mockName, final boolean transactionExists) { - Cache mockCache = mock(Cache.class, String.format("%1$s.MockCache", mockName)); - - CacheTransactionManager mockCacheTransactionManager = mock(CacheTransactionManager.class, String.format( - "%1$s.MockCacheTransactionManager", mockName)); - - when(mockCache.getCacheTransactionManager()).thenReturn(mockCacheTransactionManager); - when(mockCacheTransactionManager.exists()).thenReturn(transactionExists); - - return mockCache; - } - - protected EntityInformation mockEntityInformation() { - EntityInformation mockEntityInformation = mock(EntityInformation.class); - - doAnswer(new Answer() { - private final AtomicLong idSequence = new AtomicLong(0l); - @Override public Long answer(final InvocationOnMock invocation) throws Throwable { - Animal argument = Animal.class.cast(invocation.getArguments()[0]); - Long id = argument.getId(); - id = (id != null ? id : idSequence.incrementAndGet()); - argument.setId(id); - return id; - - } - }).when(mockEntityInformation).getId(any(Animal.class)); - - return mockEntityInformation; - } - - protected Region mockRegion(final String mockName, final Cache mockCache, final DataPolicy dataPolicy) { - Region mockRegion = mock(Region.class, String.format("%1$s.MockRegion", mockName)); - - when(mockRegion.getRegionService()).thenReturn(mockCache); - - RegionAttributes mockRegionAttributes = mock(RegionAttributes.class, String.format( - "%1$s.MockRegionAttributes", mockName)); - - when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes); - when(mockRegionAttributes.getDataPolicy()).thenReturn(dataPolicy); - - return mockRegion; - } - - @Test - public void testSave() { - Region mockRegion = mock(Region.class, "testSave"); - - SimpleGemfireRepository repository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - Animal dog = repository.save(createAnimal("dog")); - - assertNotNull(dog); - assertEquals(1l, dog.getId().longValue()); - assertEquals("dog", dog.getName()); - - verify(mockRegion, times(1)).put(eq(1l), eq(dog)); - } - - @Test - public void testSaveEntities() { - List animals = new ArrayList(3); - - animals.add(createAnimal("bird")); - animals.add(createAnimal("cat")); - animals.add(createAnimal("dog")); - - Region mockRegion = mock(Region.class, "testSaveAll"); - - SimpleGemfireRepository repository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - Iterable savedAnimals = repository.save(animals); - - assertNotNull(savedAnimals); - - verify(mockRegion, times(1)).putAll(eq(asMap(savedAnimals))); - } - - @Test - public void testSaveWrapper() { - Animal dog = createAnimal(1l, "dog"); - - Wrapper dogWrapper = new Wrapper(dog, dog.getId()); - - Region mockRegion = mock(Region.class, "testSaveWrapper"); - - SimpleGemfireRepository repository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - repository.save(dogWrapper); - - verify(mockRegion, times(1)).put(eq(dog.getId()), eq(dog)); - } - - @Test - public void testExists() { - final Animal dog = createAnimal(1l, "dog"); - - Region mockRegion = mock(Region.class, "testFindOne"); - - when(mockRegion.get(any(Long.class))).then(new Answer() { - @Override public Animal answer(final InvocationOnMock invocation) throws Throwable { - return (dog.getId().equals(invocation.getArguments()[0]) ? dog : null); - } - }); - - SimpleGemfireRepository repository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - assertTrue(repository.exists(1l)); - assertFalse(repository.exists(10l)); - } - - @Test - public void testFindOne() { - final Animal dog = createAnimal(1l, "dog"); - - Region mockRegion = mock(Region.class, "testFindOne"); - - when(mockRegion.get(any(Long.class))).then(new Answer() { - @Override public Animal answer(final InvocationOnMock invocation) throws Throwable { - return (dog.getId().equals(invocation.getArguments()[0]) ? dog : null); - } - }); - - SimpleGemfireRepository repository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - assertEquals(dog, repository.findOne(1l)); - assertNull(repository.findOne(10l)); - } - - @Test - public void testFindAll() { - long id = 0; - - final List animals = new ArrayList(3); - - animals.add(createAnimal(++id, "bird")); - animals.add(createAnimal(++id, "cat")); - animals.add(createAnimal(++id, "dog")); - - Region mockRegion = mock(Region.class, "testSaveAll"); - - when(mockRegion.getAll(any(Collection.class))).then(new Answer>() { - @Override public Map answer(final InvocationOnMock invocation) throws Throwable { - Collection keys = (Collection) invocation.getArguments()[0]; - Map result = new HashMap(keys.size()); - for (Animal animal : animals) { - if (keys.contains(animal.getId())) { - result.put(animal.getId(), animal); - } - } - return result; - } - }); - - SimpleGemfireRepository repository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - Collection animalsFound = repository.findAll(Arrays.asList(1l, 3l)); - - assertNotNull(animalsFound); - assertEquals(2, animalsFound.size()); - assertTrue(animalsFound.containsAll(CollectionUtils.subList(animals, 0, 2))); - - verify(mockRegion, times(1)).getAll(eq(Arrays.asList(1l, 3l))); - } - - @Test - public void testDeleteById() { - Region mockRegion = mock(Region.class, "testDeleteById"); - - SimpleGemfireRepository repository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - repository.delete(1l); - - verify(mockRegion, times(1)).remove(eq(1l)); - } - - @Test - public void testDeleteEntity() { - Region mockRegion = mock(Region.class, "testDeleteEntity"); - - SimpleGemfireRepository repository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - repository.delete(createAnimal(1l, "dog")); - - verify(mockRegion, times(1)).remove(eq(1l)); - } - - @Test - public void testDeleteEntities() { - Region mockRegion = mock(Region.class, "testDeleteEntities"); - - SimpleGemfireRepository repository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - repository.delete(Arrays.asList(createAnimal(1l, "bird"), createAnimal(2l, "cat"), createAnimal(3l, "dog"))); - - verify(mockRegion, times(1)).remove(eq(1l)); - verify(mockRegion, times(1)).remove(eq(2l)); - verify(mockRegion, times(1)).remove(eq(3l)); - } - - @Test - public void testDeleteAllWithClear() { - Cache mockCache = mockCache("testDeleteAllWithClear.MockCache", false); - - Region mockRegion = mockRegion("testDeleteAllWithClear.MockRegion", - mockCache, DataPolicy.REPLICATE); - - SimpleGemfireRepository gemfireRepository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - gemfireRepository.deleteAll(); - - verify(mockCache, times(1)).getCacheTransactionManager(); - verify(mockRegion, times(2)).getAttributes(); - verify(mockRegion, times(2)).getRegionService(); - verify(mockRegion, times(1)).clear(); - } - - @Test - public void testDeleteAllWithKeysWhenClearThrowsException() { - Cache mockCache = mockCache("testDeleteAllWithKeysWhenClearThrowsException.MockCache", false); - - Region mockRegion = mockRegion("testDeleteAllWithKeysWhenClearThrowsException.MockRegion", - mockCache, DataPolicy.PERSISTENT_REPLICATE); - - Set keys = new HashSet(Arrays.asList(1l, 2l, 3l)); - - doThrow(new UnsupportedOperationException("Not Implemented!")).when(mockRegion).clear(); - when(mockRegion.keySet()).thenReturn(keys); - - SimpleGemfireRepository gemfireRepository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - gemfireRepository.deleteAll(); - - verify(mockCache, times(1)).getCacheTransactionManager(); - verify(mockRegion, times(2)).getAttributes(); - verify(mockRegion, times(2)).getRegionService(); - verify(mockRegion, times(1)).clear(); - verify(mockRegion, times(1)).removeAll(eq(keys)); - } - - @Test - public void testDeleteAllWithKeysWhenPartitionRegion() { - Cache mockCache = mockCache("testDeleteAllWithKeysWhenPartitionRegion.MockCache", false); - - Region mockRegion = mockRegion("testDeleteAllWithKeysWhenPartitionRegion.MockRegion", - mockCache, DataPolicy.PERSISTENT_PARTITION); - - Set keys = new HashSet(Arrays.asList(1l, 2l, 3l)); - - when(mockRegion.keySet()).thenReturn(keys); - - SimpleGemfireRepository gemfireRepository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - gemfireRepository.deleteAll(); - - verify(mockCache, times(0)).getCacheTransactionManager(); - verify(mockRegion, times(2)).getAttributes(); - verify(mockRegion, times(0)).getRegionService(); - verify(mockRegion, times(0)).clear(); - verify(mockRegion, times(1)).removeAll(eq(keys)); - } - - @Test - public void testDeleteAllWithKeysWhenTransactionPresent() { - Cache mockCache = mockCache("testDeleteAllWithKeysWhenTransactionPresent.MockCache", true); - - Region mockRegion = mockRegion("testDeleteAllWithKeysWhenTransactionPresent.MockRegion", - mockCache, DataPolicy.REPLICATE); - - Set keys = new HashSet(Arrays.asList(1l, 2l, 3l)); - - when(mockRegion.keySet()).thenReturn(keys); - - SimpleGemfireRepository gemfireRepository = new SimpleGemfireRepository( - createGemfireTemplate(mockRegion), mockEntityInformation()); - - gemfireRepository.deleteAll(); - - verify(mockCache, times(1)).getCacheTransactionManager(); - verify(mockRegion, times(2)).getAttributes(); - verify(mockRegion, times(2)).getRegionService(); - verify(mockRegion, times(0)).clear(); - verify(mockRegion, times(1)).removeAll(eq(keys)); - } -} diff --git a/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryUnitTests.java b/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryUnitTests.java new file mode 100644 index 00000000..41eba242 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/repository/support/SimpleGemfireRepositoryUnitTests.java @@ -0,0 +1,496 @@ +/* + * 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.repository.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +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.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.CacheTransactionManager; +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionAttributes; +import org.apache.geode.cache.query.SelectResults; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.springframework.data.gemfire.GemfireTemplate; +import org.springframework.data.gemfire.repository.Wrapper; +import org.springframework.data.gemfire.repository.sample.Animal; +import org.springframework.data.repository.core.EntityInformation; + +/** + * Unit tests for {@link SimpleGemfireRepository}. + * + * @author John Blum + * @see org.junit.Rule + * @see org.junit.Test + * @see org.mockito.Mockito + * @see org.springframework.data.gemfire.GemfireTemplate + * @see org.springframework.data.gemfire.repository.Wrapper + * @see org.springframework.data.gemfire.repository.support.SimpleGemfireRepository + * @since 1.4.5 + */ +@SuppressWarnings("unchecked") +public class SimpleGemfireRepositoryUnitTests { + + @Rule + public ExpectedException exception = ExpectedException.none(); + + protected Map asMap(Iterable animals) { + Map animalMap = new HashMap<>(); + + for (Animal animal : animals) { + animalMap.put(animal.getId(), animal); + } + + return animalMap; + } + + protected Animal newAnimal(String name) { + Animal animal = new Animal(); + animal.setName(name); + return animal; + } + + protected Animal newAnimal(Long id, String name) { + Animal animal = newAnimal(name); + animal.setId(id); + return animal; + } + + protected GemfireTemplate newGemfireTemplate(Region region) { + return new GemfireTemplate(region); + } + + protected Cache mockCache(String name, boolean transactionExists) { + Cache mockCache = mock(Cache.class, String.format("%s.MockCache", name)); + + CacheTransactionManager mockCacheTransactionManager = mock(CacheTransactionManager.class, + String.format("%s.MockCacheTransactionManager", name)); + + when(mockCache.getCacheTransactionManager()).thenReturn(mockCacheTransactionManager); + when(mockCacheTransactionManager.exists()).thenReturn(transactionExists); + + return mockCache; + } + + protected EntityInformation mockEntityInformation() { + EntityInformation mockEntityInformation = mock(EntityInformation.class); + + doAnswer(new Answer() { + private final AtomicLong idSequence = new AtomicLong(0L); + + @Override + public Long answer(InvocationOnMock invocation) throws Throwable { + Animal argument = invocation.getArgumentAt(0, Animal.class); + Long id = argument.getId(); + id = (id != null ? id : idSequence.incrementAndGet()); + argument.setId(id); + return id; + + } + }).when(mockEntityInformation).getId(any(Animal.class)); + + return mockEntityInformation; + } + + protected Region mockRegion() { + return mockRegion("MockRegion"); + } + + protected Region mockRegion(String name) { + Region mockRegion = mock(Region.class, String.format("%s.MockRegion", name)); + + when(mockRegion.getName()).thenReturn(name); + when(mockRegion.getFullPath()).thenReturn(String.format("%1$s%2$s", Region.SEPARATOR, name)); + + return mockRegion; + } + + protected Region mockRegion(String name, Cache mockCache, DataPolicy dataPolicy) { + Region mockRegion = mockRegion(name); + + when(mockRegion.getRegionService()).thenReturn(mockCache); + + RegionAttributes mockRegionAttributes = mock(RegionAttributes.class, + String.format("%s.MockRegionAttributes", name)); + + when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes); + when(mockRegionAttributes.getDataPolicy()).thenReturn(dataPolicy); + + return mockRegion; + } + + @Test + public void constructSimpleGemfireRepositoryWithNullTemplateThrowsIllegalArgumentException() { + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("Template must not be null"); + + new SimpleGemfireRepository<>(null, mockEntityInformation()); + } + + @Test + public void constructSimpleGemfireRepositoryWithNullEntityInformationThrowsIllegalArgumentException() { + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("EntityInformation must not be null"); + + new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion()), null); + } + + @Test + public void testSave() { + Region mockRegion = mockRegion(); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + Animal dog = repository.save(newAnimal("dog")); + + assertNotNull(dog); + assertEquals(1L, dog.getId().longValue()); + assertEquals("dog", dog.getName()); + + verify(mockRegion, times(1)).put(eq(1L), eq(dog)); + } + + @Test + public void testSaveEntities() { + List animals = new ArrayList<>(3); + + animals.add(newAnimal("bird")); + animals.add(newAnimal("cat")); + animals.add(newAnimal("dog")); + + Region mockRegion = mockRegion(); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + Iterable savedAnimals = repository.save(animals); + + assertNotNull(savedAnimals); + + verify(mockRegion, times(1)).putAll(eq(asMap(savedAnimals))); + } + + @Test + public void testSaveWrapper() { + Animal dog = newAnimal(1L, "dog"); + + Wrapper dogWrapper = new Wrapper(dog, dog.getId()); + + Region mockRegion = mockRegion(); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + assertThat(repository.save(dogWrapper)).isEqualTo(dog); + + verify(mockRegion, times(1)).put(eq(dog.getId()), eq(dog)); + } + + @Test + public void countReturnsNumberOfRegionEntries() { + Region mockRegion = mockRegion("Example"); + GemfireTemplate template = spy(newGemfireTemplate(mockRegion)); + SelectResults mockSelectResults = mock(SelectResults.class); + + doReturn(mockSelectResults).when(template).find(eq("SELECT count(*) FROM /Example")); + when(mockSelectResults.iterator()).thenReturn(Collections.singletonList(21).iterator()); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + template, mockEntityInformation()); + + assertThat(repository.count()).isEqualTo(21); + + verify(mockRegion, times(1)).getFullPath(); + verify(template, times(1)).find(eq("SELECT count(*) FROM /Example")); + verify(mockSelectResults, times(1)).iterator(); + } + + @Test + public void testExists() { + Animal dog = newAnimal(1L, "dog"); + + Region mockRegion = mockRegion(); + + when(mockRegion.get(any(Long.class))).then( + invocation -> (dog.getId().equals(invocation.getArguments()[0]) ? dog : null)); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + assertTrue(repository.exists(1L)); + assertFalse(repository.exists(10L)); + } + + @Test + public void testFindOne() { + Animal dog = newAnimal(1L, "dog"); + + Region mockRegion = mockRegion(); + + when(mockRegion.get(any(Long.class))).then( + invocation -> (dog.getId().equals(invocation.getArguments()[0]) ? dog : null)); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + assertEquals(dog, repository.findOne(1L)); + assertNull(repository.findOne(10L)); + } + + @Test + public void testFindAll() { + Map animals = Stream.of(newAnimal(1L, "bird"), newAnimal(2L, "cat"), + newAnimal(3L, "dog")).collect(Collectors.toMap(Animal::getId, Function.identity())); + + Region mockRegion = mockRegion(); + + when(mockRegion.getAll(any(Collection.class))).then(invocation -> { + Collection keys = invocation.getArgumentAt(0, Collection.class); + + return animals.values().stream().filter((animal -> keys.contains(animal.getId()))) + .collect(Collectors.toMap(Animal::getId, Function.identity())); + }); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + Collection animalsFound = repository.findAll(Arrays.asList(1L, 3L)); + + assertThat(animalsFound).isNotNull(); + assertThat(animalsFound).hasSize(2); + assertThat(animalsFound).contains(animals.get(1L), animals.get(3L)); + + verify(mockRegion, times(1)).getAll(eq(Arrays.asList(1L, 3L))); + } + + @Test + public void findAllWithIdsReturnsNoMatches() { + Region mockRegion = mockRegion(); + + when(mockRegion.getAll(any(Collection.class))).then(invocation -> { + Collection keys = invocation.getArgumentAt(0, Collection.class); + Map result = new HashMap<>(keys.size()); + + for (Long key : keys) { + result.put(key, null); + } + + return result; + }); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + Collection animalsFound = repository.findAll(Arrays.asList(1L, 2L, 3L)); + + assertThat(animalsFound).isNotNull(); + assertThat(animalsFound).isEmpty(); + + verify(mockRegion, times(1)).getAll(eq(Arrays.asList(1L, 2L, 3L))); + } + + @Test + public void findAllWithIdsReturnsPartialMatches() { + Map animals = Stream.of(newAnimal(1L, "bird"), newAnimal(2L, "cat"), + newAnimal(3L, "dog")).collect(Collectors.toMap(Animal::getId, Function.identity())); + + Region mockRegion = mockRegion(); + + when(mockRegion.getAll(any(Collection.class))).then(invocation -> { + Collection keys = invocation.getArgumentAt(0, Collection.class); + Map result = new HashMap<>(keys.size()); + + for (Long key : keys) { + result.put(key, animals.get(key)); + } + + return result; + }); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + Collection animalsFound = repository.findAll(Arrays.asList(0L, 1L, 2L, 4L)); + + assertThat(animalsFound).isNotNull(); + assertThat(animalsFound).hasSize(2); + assertThat(animalsFound).contains(animals.get(1L), animals.get(2L)); + + verify(mockRegion, times(1)).getAll(eq(Arrays.asList(0L, 1L, 2L, 4L))); + } + + @Test + public void testDeleteById() { + Region mockRegion = mockRegion(); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + repository.delete(1L); + + verify(mockRegion, times(1)).remove(eq(1L)); + } + + @Test + public void testDeleteEntity() { + Region mockRegion = mockRegion(); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + repository.delete(newAnimal(1L, "dog")); + + verify(mockRegion, times(1)).remove(eq(1L)); + } + + @Test + public void testDeleteEntities() { + Region mockRegion = mockRegion(); + + SimpleGemfireRepository repository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + repository.delete(Arrays.asList(newAnimal(1L, "bird"), newAnimal(2L, "cat"), + newAnimal(3L, "dog"))); + + verify(mockRegion, times(1)).remove(eq(1L)); + verify(mockRegion, times(1)).remove(eq(2L)); + verify(mockRegion, times(1)).remove(eq(3L)); + } + + @Test + public void testDeleteAllWithClear() { + Cache mockCache = mockCache("MockCache", false); + + Region mockRegion = mockRegion("MockRegion", mockCache, DataPolicy.REPLICATE); + + SimpleGemfireRepository gemfireRepository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + gemfireRepository.deleteAll(); + + verify(mockCache, times(1)).getCacheTransactionManager(); + verify(mockRegion, times(2)).getAttributes(); + verify(mockRegion, times(2)).getRegionService(); + verify(mockRegion, times(1)).clear(); + } + + @Test + public void testDeleteAllWithKeysWhenClearThrowsException() { + Cache mockCache = mockCache("MockCache", false); + + Region mockRegion = mockRegion("MockRegion", mockCache, DataPolicy.PERSISTENT_REPLICATE); + + Set keys = new HashSet<>(Arrays.asList(1L, 2L, 3L)); + + doThrow(new UnsupportedOperationException("Not Implemented!")).when(mockRegion).clear(); + when(mockRegion.keySet()).thenReturn(keys); + + SimpleGemfireRepository gemfireRepository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + gemfireRepository.deleteAll(); + + verify(mockCache, times(1)).getCacheTransactionManager(); + verify(mockRegion, times(2)).getAttributes(); + verify(mockRegion, times(2)).getRegionService(); + verify(mockRegion, times(1)).clear(); + verify(mockRegion, times(1)).removeAll(eq(keys)); + } + + @Test + public void testDeleteAllWithKeysWhenPartitionRegion() { + Cache mockCache = mockCache("MockCache", false); + + Region mockRegion = mockRegion("MockRegion", mockCache, DataPolicy.PERSISTENT_PARTITION); + + Set keys = new HashSet<>(Arrays.asList(1L, 2L, 3L)); + + when(mockRegion.keySet()).thenReturn(keys); + + SimpleGemfireRepository gemfireRepository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + gemfireRepository.deleteAll(); + + verify(mockCache, times(0)).getCacheTransactionManager(); + verify(mockRegion, times(2)).getAttributes(); + verify(mockRegion, times(0)).getRegionService(); + verify(mockRegion, times(0)).clear(); + verify(mockRegion, times(1)).removeAll(eq(keys)); + } + + @Test + public void testDeleteAllWithKeysWhenTransactionPresent() { + Cache mockCache = mockCache("MockCache", true); + + Region mockRegion = mockRegion("MockRegion", mockCache, DataPolicy.REPLICATE); + + Set keys = new HashSet<>(Arrays.asList(1L, 2L, 3L)); + + when(mockRegion.keySet()).thenReturn(keys); + + SimpleGemfireRepository gemfireRepository = new SimpleGemfireRepository<>( + newGemfireTemplate(mockRegion), mockEntityInformation()); + + gemfireRepository.deleteAll(); + + verify(mockCache, times(1)).getCacheTransactionManager(); + verify(mockRegion, times(2)).getAttributes(); + verify(mockRegion, times(2)).getRegionService(); + verify(mockRegion, times(0)).clear(); + verify(mockRegion, times(1)).removeAll(eq(keys)); + } +}