SGF-507 - Handle case-insensitive OQL queries defined as Repository query methods.

(cherry picked from commit 96a5990749a76f1369cecaa54f4d98196f6688ac)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
John Blum
2016-07-18 15:17:26 -07:00
parent 5586eebe15
commit f95e97186f
21 changed files with 632 additions and 331 deletions

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.gemfire.repository.query;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -27,8 +28,9 @@ import org.springframework.data.repository.query.parser.PartTree;
/**
* Unit tests for {@link GemfireQueryCreator}.
*
*
* @author Oliver Gierke
* @author John Blum
*/
public class GemfireQueryCreatorUnitTests {
@@ -37,18 +39,28 @@ public class GemfireQueryCreatorUnitTests {
@Before
@SuppressWarnings("unchecked")
public void setUp() {
GemfireMappingContext context = new GemfireMappingContext();
entity = (GemfirePersistentEntity<Person>) context.getPersistentEntity(Person.class);
entity = (GemfirePersistentEntity<Person>) new GemfireMappingContext().getPersistentEntity(Person.class);
}
@Test
public void createsQueryForSimplePropertyReferenceCorrectly() {
PartTree partTree = new PartTree("findByLastname", Person.class);
PartTree partTree = new PartTree("findByFirstname", Person.class);
GemfireQueryCreator creator = new GemfireQueryCreator(partTree, entity);
GemfireQueryCreator queryCreator = new GemfireQueryCreator(partTree, entity);
QueryString query = creator.createQuery();
assertThat(query.toString(), is("SELECT * FROM /simple x WHERE x.firstname = $1"));
QueryString query = queryCreator.createQuery();
assertThat(query.toString(), is(equalTo("SELECT * FROM /simple x WHERE x.lastname = $1")));
}
@Test
public void createsQueryForNestedPropertyReferenceCorrectly() {
PartTree partTree = new PartTree("findPersonByAddressCity", Person.class);
GemfireQueryCreator queryCreator = new GemfireQueryCreator(partTree, entity);
QueryString query = queryCreator.createQuery();
assertThat(query.toString(), is(equalTo("SELECT * FROM /simple x WHERE x.address.city = $1")));
}
}

View File

@@ -16,9 +16,12 @@
package org.springframework.data.gemfire.repository.query;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;
import java.lang.reflect.Method;
@@ -47,7 +50,7 @@ import org.springframework.util.ObjectUtils;
/**
* Unit tests for {@link GemfireQueryMethod}.
*
*
* @author Oliver Gierke
* @author John Blum
*/
@@ -58,7 +61,7 @@ public class GemfireQueryMethodUnitTests {
public ExpectedException expectedException = ExpectedException.none();
private GemfireMappingContext context = new GemfireMappingContext();
private ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
@Mock
@@ -115,6 +118,7 @@ public class GemfireQueryMethodUnitTests {
}
@Before
@SuppressWarnings("unchecked")
public void setup() {
when(metadata.getDomainType()).thenReturn((Class) Person.class);
when(metadata.getReturnedDomainClass(Mockito.any(Method.class))).thenReturn((Class) Person.class);
@@ -146,7 +150,7 @@ public class GemfireQueryMethodUnitTests {
public void rejectsQueryMethodWithPageableParameter() throws Exception {
expectedException.expect(IllegalStateException.class);
expectedException.expectCause(is(nullValue(Throwable.class)));
expectedException.expectMessage(Matchers.startsWith("Pagination is not supported by GemFire Repositories!"));
expectedException.expectMessage(Matchers.startsWith("Pagination is not supported by GemFire Repositories; Offending method: someMethod"));
new GemfireQueryMethod(Invalid.class.getMethod("someMethod", Pageable.class), metadata, factory, context);
}
@@ -280,5 +284,4 @@ public class GemfireQueryMethodUnitTests {
void unlimitedQuery();
}
}

View File

@@ -15,8 +15,9 @@
*/
package org.springframework.data.gemfire.repository.query;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertNotNull;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
@@ -28,7 +29,8 @@ import org.springframework.data.gemfire.repository.query.Predicates.AtomicPredic
import org.springframework.data.repository.query.parser.Part;
/**
*
* Unit tests for {@link Predicates}.
*
* @author Oliver Gierke
* @author John Blum
*/
@@ -37,49 +39,67 @@ public class PredicatesUnitTests {
@Test
public void atomicPredicateDefaultsAlias() {
Part part = new Part("firstname", Person.class);
Iterable<Integer> indexes = Arrays.asList(1);
Iterator<Integer> indexes = Collections.singletonList(1).iterator();
Predicate predicate = new AtomicPredicate(part, indexes);
Predicate predicate = new AtomicPredicate(part, indexes.iterator());
assertThat(predicate.toString(null), is("x.firstname = $1"));
}
@Test
public void concatenatesAndPredicateCorrectly() {
Part left = new Part("firstname", Person.class);
Part right = new Part("lastname", Person.class);
Iterator<Integer> indexes = Arrays.asList(1, 2).iterator();
Predicates predicate = Predicates.create(left, indexes);
predicate = predicate.and(new AtomicPredicate(right, indexes));
Predicate predicate = Predicates.create(left, indexes).and(Predicates.create(right, indexes));
assertThat(predicate, is(notNullValue(Predicate.class)));
assertThat(predicate.toString(null), is("x.firstname = $1 AND x.lastname = $2"));
}
@Test
public void concatenatesOrPredicateCorrectly() {
Part left = new Part("firstname", Person.class);
Part right = new Part("lastname", Person.class);
Iterator<Integer> indexes = Arrays.asList(1, 2).iterator();
Predicates predicate = Predicates.create(left, indexes);
predicate = predicate.or(new AtomicPredicate(right, indexes));
Predicate predicate = Predicates.create(left, indexes).or(Predicates.create(right, indexes));
assertThat(predicate.toString(null), is("x.firstname = $1 OR x.lastname = $2"));
assertThat(predicate, is(notNullValue(Predicate.class)));
assertThat(predicate.toString(null), is(equalTo("x.firstname = $1 OR x.lastname = $2")));
}
@Test
public void testBooleanBasedPredicate() {
public void handlesBooleanBasedPredicateCorrectly() {
Part part = new Part("activeTrue", User.class);
Iterator<Integer> indexes = Collections.<Integer>emptyList().iterator();
Iterator<Integer> indexes = Collections.singletonList(1).iterator();
Predicates predicate = Predicates.create(part, indexes);
assertNotNull(predicate);
assertThat(predicate.toString("user"), is("user.active = true"));
assertThat(predicate, is(notNullValue(Predicate.class)));
assertThat(predicate.toString("user"), is(equalTo("user.active = true")));
}
/**
* @link https://jira.spring.io/browse/SGF-507
*/
@Test
public void handlesIgnoreCasePredicateCorrectly() {
Part left = new Part("firstnameIgnoreCase", Person.class);
Part right = new Part("lastnameIgnoreCase", Person.class);
Iterator<Integer> indexes = Arrays.asList(1, 2).iterator();
Predicate predicate = Predicates.create(left, indexes).and(Predicates.create(right, indexes));
assertThat(predicate, is(notNullValue(Predicate.class)));
assertThat(predicate.toString("person"), is(equalTo("person.firstname.equalsIgnoreCase($1) AND person.lastname.equalsIgnoreCase($2)")));
}
static class Person {
@@ -87,9 +107,9 @@ public class PredicatesUnitTests {
String lastname;
}
// TODO refactor Person to include boolean state; remove User
static class User {
Boolean active;
String username;
}
}

View File

@@ -44,7 +44,7 @@ public class IncompatibleRegionKeyEntityIdAnimalRepositoryTest {
"IncompatibleRegionKeyEntityIdAnimalRepositoryTest-context.xml");
@Test(expected = IllegalArgumentException.class)
public void testStoreAnimalHavingLongIdInRabbitsRegionWithStringKey() {
public void storeAnimalHavingLongIdInRabbitsRegionWithStringKey() {
try {
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext(
APPLICATION_CONTEXT_CONFIG_LOCATION);
@@ -62,10 +62,9 @@ public class IncompatibleRegionKeyEntityIdAnimalRepositoryTest {
catch (BeanCreationException expected) {
//expected.printStackTrace(System.err);
assertTrue(expected.getCause() instanceof IllegalArgumentException);
assertEquals(String.format("The Region referenced only supports keys of type %1$s but the entity to be stored has an id of type %2$s!",
String.class, Long.class), expected.getCause().getMessage());
assertEquals(String.format("The Region referenced only supports keys of type %1$s, but the entity to be stored has an id of type %2$s",
String.class.getName(), Long.class.getName()), expected.getCause().getMessage());
throw (IllegalArgumentException) expected.getCause();
}
}
}

View File

@@ -21,10 +21,11 @@ import java.util.List;
import org.springframework.data.domain.Sort;
import org.springframework.data.gemfire.repository.GemfireRepository;
import org.springframework.data.gemfire.repository.Query;
import org.springframework.data.gemfire.repository.query.annotation.Trace;
/**
* Sample Repository interface managing {@link Person}s.
*
*
* @author Oliver Gierke
* @author David Turanski
* @author John Blum
@@ -39,23 +40,26 @@ public interface PersonRepository extends GemfireRepository<Person, Long> {
Collection<Person> findByFirstname(String firstname);
Collection<Person> findByFirstnameIn(Collection<String> firstnames);
Collection<Person> findByFirstnameContaining(String firstName);
Collection<Person> findByFirstnameIn(String... firstnames);
Collection<Person> findByFirstnameIn(Collection<String> firstNames);
Collection<Person> findByFirstnameAndLastname(String firstname, String lastname);
Collection<Person> findByFirstnameIn(String... firstNames);
Collection<Person> findByFirstnameOrLastname(String firstname, String lastname);
Collection<Person> findByFirstnameLike(String firstName);
Person findByLastname(String lastname);
Collection<Person> findByFirstnameStartingWith(String firstName);
Collection<Person> findByFirstnameLike(String firstname);
Collection<Person> findByFirstnameAndLastname(String firstName, String lastName);
Collection<Person> findByFirstnameStartingWith(String firstname);
@Trace
Collection<Person> findByFirstnameIgnoreCaseAndLastnameIgnoreCase(String firstName, String lastName);
Collection<Person> findByLastnameEndingWith(String lastname);
Collection<Person> findByFirstnameOrLastname(String firstName, String lastName);
Collection<Person> findByFirstnameContaining(String firstname);
Person findByLastname(String lastName);
Collection<Person> findByLastnameEndingWith(String lastName);
List<Person> findDistinctByLastname(String lastName, Sort order);

View File

@@ -16,19 +16,34 @@
package org.springframework.data.gemfire.repository.sample;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicLong;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.RegionAttributes;
import org.junit.Before;
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.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.domain.Sort;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.LocalRegionFactoryBean;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -44,75 +59,142 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @since 1.4.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PersonRepositoryTest.GemFireConfiguration.class)
@SuppressWarnings("unused")
public class PersonRepositoryTest {
private static final String GEMFIRE_LOG_LEVEL = System.getProperty("gemfire.log-level", "warning");
protected final AtomicLong ID_SEQUENCE = new AtomicLong(0l);
private Person cookieDoe = createPerson("Cookie", "Doe");
private Person janeDoe = createPerson("Jane", "Doe");
private Person jonDoe = createPerson("Jon", "Doe");
private Person pieDoe = createPerson("Pie", "Doe");
private Person jackHandy = createPerson("Jack", "Handy");
private Person sandyHandy = createPerson("Sandy", "Handy");
private Person imaPigg = createPerson("Ima", "Pigg");
private Person cookieDoe = newPerson("Cookie", "Doe");
private Person janeDoe = newPerson("Jane", "Doe");
private Person jonDoe = newPerson("Jon", "Doe");
private Person pieDoe = newPerson("Pie", "Doe");
private Person jackHandy = newPerson("Jack", "Handy");
private Person sandyHandy = newPerson("Sandy", "Handy");
private Person imaPigg = newPerson("Ima", "Pigg");
@Autowired
private PersonRepository personRepo;
private PersonRepository personRepository;
@Before
public void setup() {
if (personRepo.count() == 0) {
sandyHandy = personRepo.save(sandyHandy);
jonDoe = personRepo.save(jonDoe);
jackHandy = personRepo.save(jackHandy);
janeDoe = personRepo.save(janeDoe);
pieDoe = personRepo.save(pieDoe);
imaPigg = personRepo.save(imaPigg);
cookieDoe = personRepo.save(cookieDoe);
if (personRepository.count() == 0) {
sandyHandy = personRepository.save(sandyHandy);
jonDoe = personRepository.save(jonDoe);
jackHandy = personRepository.save(jackHandy);
janeDoe = personRepository.save(janeDoe);
pieDoe = personRepository.save(pieDoe);
imaPigg = personRepository.save(imaPigg);
cookieDoe = personRepository.save(cookieDoe);
}
assertEquals(7l, personRepo.count());
assertThat(personRepository.count(), is(equalTo(7L)));
}
protected Person createPerson(final String firstName, final String lastName) {
protected Person newPerson(String firstName, String lastName) {
return new Person(ID_SEQUENCE.incrementAndGet(), firstName, lastName);
}
protected Sort.Order createOrder(final String property) {
return createOrder(property, Sort.Direction.ASC);
protected Sort.Order newOrder(String property) {
return newOrder(property, Sort.Direction.ASC);
}
protected Sort.Order createOrder(final String property, final Sort.Direction direction) {
protected Sort.Order newOrder(String property, Sort.Direction direction) {
return new Sort.Order(direction, property);
}
protected Sort createSort(final Sort.Order... orders) {
protected Sort newSort(Sort.Order... orders) {
return new Sort(orders);
}
@Test
public void testFindDistinctPeopleWithOrder() {
List<Person> actualPeople = personRepo.findDistinctPeopleByOrderByLastnameDesc(
createSort(createOrder("firstname")));
public void findDistinctPeopleOrderedByFirstnameDescending() {
List<Person> actualPeople = personRepository.findDistinctPeopleByOrderByLastnameDesc(
newSort(newOrder("firstname")));
assertNotNull(actualPeople);
assertFalse(actualPeople.isEmpty());
assertEquals(7, actualPeople.size());
assertEquals(Arrays.asList(imaPigg, jackHandy, sandyHandy, cookieDoe, janeDoe, jonDoe, pieDoe), actualPeople);
assertThat(actualPeople, is(notNullValue(List.class)));
assertThat(actualPeople.size(), is(equalTo(7)));
assertThat(actualPeople, is(equalTo(Arrays.asList(
imaPigg, jackHandy, sandyHandy, cookieDoe, janeDoe, jonDoe, pieDoe))));
}
@Test
public void testFindDistinctPersonWithNoOrder() {
List<Person> actualPeople = personRepo.findDistinctByLastname("Pigg", null);
public void findDistinctPersonWithUnordered() {
List<Person> actualPeople = personRepository.findDistinctByLastname("Handy", null);
assertNotNull(actualPeople);
assertFalse(actualPeople.isEmpty());
assertEquals(1, actualPeople.size());
assertEquals(String.format("Expected '%1$s'; but was '%2$s'", imaPigg, actualPeople.get(0)),
imaPigg, actualPeople.get(0));
assertThat(actualPeople, is(notNullValue(List.class)));
assertThat(actualPeople.size(), is(equalTo(2)));
assertThat(String.format("Expected '%1$s'; but was '%2$s'", Arrays.asList(jackHandy, sandyHandy), actualPeople),
actualPeople, contains(jackHandy, sandyHandy));
}
@Test
public void findPersonByFirstAndLastNameIgnoringCase() {
Collection<Person> people = personRepository.findByFirstnameIgnoreCaseAndLastnameIgnoreCase("jON", "doE");
assertThat(people, is(notNullValue(Collection.class)));
assertThat(people.size(), is(equalTo(1)));
assertThat(people.iterator().next(), is(equalTo(jonDoe)));
}
@Configuration
@EnableGemfireRepositories(basePackages = "org.springframework.data.gemfire.repository.sample",
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
value = org.springframework.data.gemfire.repository.sample.PersonRepository.class))
public static class GemFireConfiguration {
String applicationName() {
return PersonRepositoryTest.class.getSimpleName();
}
String logLevel() {
return GEMFIRE_LOG_LEVEL;
}
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", applicationName());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", logLevel());
return gemfireProperties;
}
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
@Bean(name = "simple")
LocalRegionFactoryBean simpleRegion(Cache gemfireCache, RegionAttributes<Long, Person> simpleRegionAttributes) {
LocalRegionFactoryBean<Long, Person> simpleRegion = new LocalRegionFactoryBean<Long, Person>();
simpleRegion.setAttributes(simpleRegionAttributes);
simpleRegion.setCache(gemfireCache);
simpleRegion.setClose(false);
simpleRegion.setPersistent(false);
return simpleRegion;
}
@Bean
@SuppressWarnings("unchecked")
RegionAttributesFactoryBean simpleRegionAttributes() {
RegionAttributesFactoryBean simpleRegionAttributes = new RegionAttributesFactoryBean();
simpleRegionAttributes.setKeyConstraint(Long.class);
simpleRegionAttributes.setValueConstraint(Person.class);
return simpleRegionAttributes;
}
}
}

View File

@@ -43,7 +43,7 @@ public class PlantRepositoryTest {
"PlantRepositoryTest-context.xml");
@Test(expected = IllegalArgumentException.class)
public void testStorePlantHavingStringIdInPlantsRegionWithLongKey() {
public void storePlantHavingStringIdInPlantsRegionWithLongKey() {
try {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
APPLICATION_CONTEXT_CONFIG_LOCATION);
@@ -54,10 +54,9 @@ public class PlantRepositoryTest {
catch (BeanCreationException expected) {
//expected.printStackTrace(System.err);
assertTrue(expected.getCause() instanceof IllegalArgumentException);
assertEquals(String.format("The Region referenced only supports keys of type %1$s but the entity to be stored has an id of type %2$s!",
Long.class, String.class), expected.getCause().getMessage());
assertEquals(String.format("The Region referenced only supports keys of type %1$s, but the entity to be stored has an id of type %2$s",
Long.class.getName(), String.class.getName()), expected.getCause().getMessage());
throw (IllegalArgumentException) expected.getCause();
}
}
}

View File

@@ -13,35 +13,46 @@
* 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.assertSame;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import org.hamcrest.Matchers;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.aop.framework.Advised;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.repository.GemfireRepository;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.EntityInformation;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import org.springframework.data.repository.core.RepositoryMetadata;
/**
* Unit tests for {@link GemfireRepositoryFactory}.
@@ -54,80 +65,235 @@ import com.gemstone.gemfire.cache.RegionAttributes;
@SuppressWarnings("unused")
public class GemfireRepositoryFactoryUnitTests {
@Rule
public ExpectedException exception = ExpectedException.none();
private GemfireMappingContext gemfireMappingContext = new GemfireMappingContext();
@Mock
private Region<?, ?> region;
private Region<Object, Object> mockRegion;
@Mock
@SuppressWarnings("rawtypes")
private RegionAttributes attributes;
private RegionAttributes mockRegionAttributes;
@SuppressWarnings("unchecked")
protected <K, V> Region<K, V> configureMockRegion(Region<K, V> mockRegion, String name,
Class<K> keyType, Class<V> valueType) {
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegion.getFullPath()).thenReturn(String.format("%1$s%2$s", Region.SEPARATOR, name));
when(mockRegion.getName()).thenReturn(name);
when(mockRegionAttributes.getKeyConstraint()).thenReturn(keyType);
when(mockRegionAttributes.getValueConstraint()).thenReturn(valueType);
return mockRegion;
}
@SuppressWarnings("unchecked")
protected <K, V> Region<K, V> mockRegion(String name, Class<K> keyType, Class<V> valueType) {
return configureMockRegion(mock(Region.class, name), name, keyType, valueType);
}
protected RepositoryMetadata mockRepositoryMetadata(final Class<?> domainType, final Class<?> idType,
final Class<?> repositoryInterface) {
RepositoryMetadata mockRepositoryMetadata = mock(RepositoryMetadata.class);
when(mockRepositoryMetadata.getDomainType()).then(new Answer<Class<?>>() {
@Override public Class<?> answer(InvocationOnMock invocation) throws Throwable {
return domainType;
}
});
when(mockRepositoryMetadata.getIdType()).then(new Answer<Class<?>>() {
@Override public Class<?> answer(InvocationOnMock invocation) throws Throwable {
return idType;
}
});
when(mockRepositoryMetadata.getRepositoryInterface()).then(new Answer<Class<?>>() {
@Override public Class<?> answer(InvocationOnMock invocation) throws Throwable {
return repositoryInterface;
}
});
return mockRepositoryMetadata;
}
@Before
@SuppressWarnings("unchecked")
public void setup() {
when(region.getName()).thenReturn("simple");
when(region.getFullPath()).thenReturn("/simple");
when(region.getAttributes()).thenReturn(attributes);
configureMockRegion(mockRegion, "simple", Object.class, Object.class);
}
@Test
public void constructGemfireRepositoryFactoryWithNullMappingContextThrowsIllegalArgumentException() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage("MappingContext must not be null");
new GemfireRepositoryFactory(Collections.<Region<?, ?>>emptyList(), null);
}
@Test
public void constructGemfireRepositoryFactoryWithNullRegionsThrowsIllegalArgumentException() {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage("Regions must not be null");
new GemfireRepositoryFactory(null, gemfireMappingContext);
}
@Test
public void getRepositoryRegionNameFromRepositoryInterfaceWithRegionAnnotation() {
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>emptyList(), gemfireMappingContext);
assertThat(gemfireRepositoryFactory.getRepositoryRegionName(PersonRepository.class),
is(equalTo("People")));
}
@Test
public void getRepositoryRegionNameFromRepositoryInterfaceWithoutRegionAnnotation() {
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>emptyList(), gemfireMappingContext);
assertThat(gemfireRepositoryFactory.getRepositoryRegionName(SampleCustomGemfireRepository.class),
is(nullValue(String.class)));
}
@Test
@SuppressWarnings("unchecked")
public void getTemplateReturnsGemfireTemplateForPeopleRegion() {
RepositoryMetadata mockRepositoryMetadata = mockRepositoryMetadata(Person.class, Long.class,
PersonRepository.class);
Region<Long, Person> mockPeopleRegion = mockRegion("People", Long.class, Person.class);
Iterable<Region<?, ?>> regions = Arrays.asList(mockRegion, mockPeopleRegion);
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
regions, gemfireMappingContext);
GemfireTemplate gemfireTemplate = gemfireRepositoryFactory.getTemplate(mockRepositoryMetadata);
assertThat(gemfireTemplate, is(notNullValue(GemfireTemplate.class)));
assertThat(gemfireTemplate.<Long, Person>getRegion(), is(equalTo(mockPeopleRegion)));
verify(mockPeopleRegion, times(1)).getAttributes();
verify(mockPeopleRegion, times(1)).getFullPath();
verify(mockPeopleRegion, times(1)).getName();
verify(mockRegionAttributes, times(1)).getKeyConstraint();
verify(mockRepositoryMetadata, times(1)).getDomainType();
verify(mockRepositoryMetadata, times(1)).getIdType();
}
@Test
public void getTemplateReturnsGemfireTemplateForSimpleRegion() {
RepositoryMetadata mockRepositoryMetadata = mockRepositoryMetadata(Person.class, Long.class,
SampleCustomGemfireRepository.class);
Iterable<Region<?, ?>> regions = Collections.<Region<?, ?>>singleton(mockRegion);
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
regions, gemfireMappingContext);
GemfireTemplate gemfireTemplate = gemfireRepositoryFactory.getTemplate(mockRepositoryMetadata);
assertThat(gemfireTemplate, is(notNullValue(GemfireTemplate.class)));
assertThat(gemfireTemplate.getRegion(), is(equalTo(mockRegion)));
verify(mockRepositoryMetadata, times(1)).getDomainType();
verify(mockRepositoryMetadata, times(1)).getIdType();
}
@Test
public void getTemplateThrowsIllegalArgumentExceptionForIncompatibleRegionKeyTypeAndRepositoryIdType() {
RepositoryMetadata mockRepositoryMetadata = mockRepositoryMetadata(Person.class, Long.class,
PersonRepository.class);
Region<String, Person> mockPeopleRegion = mockRegion("People", String.class, Person.class);
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>singleton(mockPeopleRegion), gemfireMappingContext);
try {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(String.format(
"The Region referenced only supports keys of type %1$s, but the entity to be stored has an id of type %2$s",
String.class.getName(), Long.class.getName()));
gemfireRepositoryFactory.getTemplate(mockRepositoryMetadata);
}
finally {
verify(mockRepositoryMetadata, times(1)).getDomainType();
verify(mockRepositoryMetadata, times(1)).getIdType();
verify(mockPeopleRegion, times(1)).getAttributes();
verify(mockPeopleRegion, times(1)).getFullPath();
verify(mockPeopleRegion, times(1)).getName();
verify(mockRegionAttributes, times(1)).getKeyConstraint();
}
}
@Test
public void getTemplateThrowsIllegalStateExceptionForRegionNotFound() {
RepositoryMetadata mockRepositoryMetadata = mockRepositoryMetadata(Person.class, Long.class,
PersonRepository.class);
GemfireRepositoryFactory gemfireRepositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>singleton(mockRegion), gemfireMappingContext);
try {
exception.expect(IllegalStateException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(String.format(
"No Region 'People' found for domain class %s; Make sure you have configured a GemFire Region of that name in your application context",
Person.class.getName()));
gemfireRepositoryFactory.getTemplate(mockRepositoryMetadata);
}
finally {
verify(mockRepositoryMetadata, times(2)).getDomainType();
verify(mockRepositoryMetadata, never()).getIdType();
verify(mockRegion, times(1)).getFullPath();
verify(mockRegion, times(1)).getName();
verifyZeroInteractions(mockRegionAttributes);
}
}
/**
* @link https://jira.spring.io/browse/SGF-112
*/
@Test(expected = IllegalStateException.class)
@Test
public void rejectsInterfacesExtendingPagingAndSortingRepository() {
GemfireRepositoryFactory repositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>singletonList(region), new GemfireMappingContext());
exception.expect(IllegalStateException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(startsWith("Pagination is not supported by GemFire Repositories"));
try {
repositoryFactory.getRepository(SamplePagingAndSortingRepository.class);
//factory.getRepository(SamplePagingRepository.class);
//factory.getRepository(SampleSortingRepository.class);
}
catch (IllegalStateException expected) {
assertThat(expected.getMessage(), Matchers.startsWith(
"Pagination is not supported by GemFire Repositories!"));
throw expected;
}
GemfireRepositoryFactory repositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>singletonList(mockRegion), new GemfireMappingContext());
repositoryFactory.getRepository(SamplePagingAndSortingRepository.class);
}
@Test
public void usesConfiguredRepositoryBaseClass() {
GemfireRepositoryFactory repositoryFactory = new GemfireRepositoryFactory(
Collections.<Region<?, ?>>singletonList(region), new GemfireMappingContext());
Collections.<Region<?, ?>>singletonList(mockRegion), new GemfireMappingContext());
repositoryFactory.setRepositoryBaseClass(CustomBaseRepository.class);
GemfireRepository<?, ?> gemfireRepository = repositoryFactory.getRepository(SampleCustomGemfireRepository.class,
new SampleCustomRepositoryImpl());
assertSame(CustomBaseRepository.class, ((Advised) gemfireRepository).getTargetClass());
assertThat(((Advised) gemfireRepository).getTargetClass(), is(equalTo((Class) CustomBaseRepository.class)));
}
interface SamplePagingAndSortingRepository extends PagingAndSortingRepository<Person, Long> {
}
interface SamplePagingRepository extends Repository<Person, Long> {
Page<Person> findAll(Pageable pageable);
}
interface SampleSortingRepository extends Repository<Person, Long> {
Iterable<Person> findAll(Sort sort);
}
interface SampleCustomRepository<T> {
void doCustomUpdate(T entity);
}
class SampleCustomRepositoryImpl<T> implements SampleCustomRepository<T> {
@Override
public void doCustomUpdate(final T entity) {
throw new UnsupportedOperationException("Not Implemented!");
}
}
interface SampleCustomGemfireRepository extends GemfireRepository<Person, Long>, SampleCustomRepository<Person> {
}
static class CustomBaseRepository<T, ID extends Serializable> extends SimpleGemfireRepository<T, ID> {
public CustomBaseRepository(GemfireTemplate template, EntityInformation<T, ID> entityInformation) {
@@ -135,4 +301,21 @@ public class GemfireRepositoryFactoryUnitTests {
}
}
interface SampleCustomRepository<T> {
void doCustomUpdate(T entity);
}
class SampleCustomRepositoryImpl<T> implements SampleCustomRepository<T> {
@Override
public void doCustomUpdate(final T entity) {
throw new UnsupportedOperationException("Not Implemented");
}
}
interface SampleCustomGemfireRepository extends GemfireRepository<Person, Long>, SampleCustomRepository<Person> {
}
@org.springframework.data.gemfire.mapping.Region("People")
interface PersonRepository extends GemfireRepository<Person, Long> {
}
}