DATAGEODE-367 - Expose EntityInformation and the GemfireTemplate on SimpleGemfireRepository.
This commit is contained in:
@@ -19,7 +19,7 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* Pivotal GemFire specific extension of the Spring Data {@link CrudRepository} interface.
|
||||
* Apache Geode extension of the Spring Data {@link CrudRepository} interface.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author John Blum
|
||||
@@ -28,10 +28,10 @@ import org.springframework.data.repository.CrudRepository;
|
||||
public interface GemfireRepository<T, ID> extends CrudRepository<T, ID> {
|
||||
|
||||
/**
|
||||
* Returns all entities sorted by the given options.
|
||||
* Returns all entities ordered by the given {@link Sort}.
|
||||
*
|
||||
* @param sort the Spring Data Commons Sort type defining the ordering criteria.
|
||||
* @return all entities sorted by the given options.
|
||||
* @param sort {@link Sort} defining the ordering criteria.
|
||||
* @return all entities ordered by the given {@link Sort}.
|
||||
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
|
||||
* @see org.springframework.data.domain.Sort
|
||||
* @see java.lang.Iterable
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.gemfire.repository.support;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -37,22 +37,31 @@ 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.gemfire.util.SpringUtils;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Basic Repository implementation for GemFire.
|
||||
* Simple, basic {@link CrudRepository} implementation for Apache Geode.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
* @see java.io.Serializable
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.CacheTransactionManager
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.data.gemfire.GemfireTemplate
|
||||
* @see org.springframework.data.gemfire.repository.GemfireRepository
|
||||
* @see org.apache.geode.cache.Cache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.data.repository.CrudRepository
|
||||
* @see org.springframework.data.repository.core.EntityInformation
|
||||
*/
|
||||
public class SimpleGemfireRepository<T, ID> implements GemfireRepository<T, ID> {
|
||||
|
||||
@@ -60,18 +69,21 @@ public class SimpleGemfireRepository<T, ID> implements GemfireRepository<T, ID>
|
||||
|
||||
private final GemfireTemplate template;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link SimpleGemfireRepository} initialized with the {@link GemfireTemplate}
|
||||
* and {@link EntityInformation}.
|
||||
*
|
||||
* @param template {@link GemfireTemplate} used to perform basic data access operations and simple OQL queries;
|
||||
* must not be {@literal null}.
|
||||
* @param entityInformation {@link EntityInformation} used to describe the entity; must not be {@literal null}.
|
||||
* @param entityInformation {@link EntityInformation} that describes the entity; must not be {@literal null}.
|
||||
* @throws IllegalArgumentException if {@link GemfireTemplate} or {@link EntityInformation} is {@literal null}.
|
||||
* @see org.springframework.data.gemfire.GemfireTemplate
|
||||
* @see org.springframework.data.repository.core.EntityInformation
|
||||
*/
|
||||
public SimpleGemfireRepository(GemfireTemplate template, EntityInformation<T, ID> entityInformation) {
|
||||
public SimpleGemfireRepository(@NonNull GemfireTemplate template,
|
||||
@NonNull EntityInformation<T, ID> entityInformation) {
|
||||
|
||||
Assert.notNull(template, "GemfireTemplate must not be null");
|
||||
Assert.notNull(entityInformation, "EntityInformation must not be null");
|
||||
@@ -80,44 +92,110 @@ public class SimpleGemfireRepository<T, ID> implements GemfireRepository<T, ID>
|
||||
this.entityInformation = entityInformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the {@link EntityInformation} type describing the entity.
|
||||
*
|
||||
* @return a reference to the {@link EntityInformation} type describing the entity.
|
||||
* @see org.springframework.data.repository.core.EntityInformation
|
||||
*/
|
||||
public @NonNull EntityInformation<T, ID> getEntityInformation() {
|
||||
return this.entityInformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the SLF4J {@link Logger} used to log the operations of this {@link GemfireRepository}.
|
||||
*
|
||||
* @return a reference to the SLF4J {@link Logger} used to log the operations of this {@link GemfireRepository}.
|
||||
* @see org.slf4j.Logger
|
||||
*/
|
||||
public @NonNull Logger getLogger() {
|
||||
return this.logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Region} to which this {@link GemfireRepository} performs all data access operations.
|
||||
*
|
||||
* @return a reference to the {@link Region} on which this {@link GemfireRepository} operates.
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see #getTemplate()
|
||||
*/
|
||||
public @NonNull Region<ID, T> getRegion() {
|
||||
return getTemplate().getRegion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the {@link GemfireTemplate} used by this {@link GemfireRepository} to perform basic
|
||||
* CRUD data access operations and simple OQL queries.
|
||||
*
|
||||
* @return a reference to the {@link GemfireTemplate} used by this {@link GemfireRepository}.
|
||||
* @see org.springframework.data.gemfire.GemfireTemplate
|
||||
*/
|
||||
public @NonNull GemfireTemplate getTemplate() {
|
||||
return this.template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U extends T> U save(U entity) {
|
||||
public <U extends T> U save(@NonNull U entity) {
|
||||
|
||||
ID id = this.entityInformation.getRequiredId(entity);
|
||||
ID id = getEntityInformation().getRequiredId(entity);
|
||||
|
||||
this.template.put(id, entity);
|
||||
// CREATE/UPDATE entity in Region
|
||||
T existingValue = getTemplate().put(id, entity);
|
||||
|
||||
if (getLogger().isDebugEnabled()) {
|
||||
getLogger().debug("Overwrote existing value [{}] for ID [{}]", existingValue, id);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T save(Wrapper<T, ID> wrapper) {
|
||||
public T save(@NonNull Wrapper<T, ID> wrapper) {
|
||||
|
||||
T entity = wrapper.getEntity();
|
||||
|
||||
this.template.put(wrapper.getKey(), entity);
|
||||
// CREATE/UPDATE entity in Region
|
||||
T existingValue = getTemplate().put(wrapper.getKey(), entity);
|
||||
|
||||
if (getLogger().isDebugEnabled()) {
|
||||
getLogger().debug("Overwrote existing value [{}] for ID [{}]", existingValue, wrapper.getKey());
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U extends T> Iterable<U> saveAll(Iterable<U> entities) {
|
||||
public <U extends T> Iterable<U> saveAll(@NonNull Iterable<U> entities) {
|
||||
|
||||
EntityInformation<T, ID> entityInformation = getEntityInformation();
|
||||
|
||||
Map<ID, U> entitiesToSave = new HashMap<>();
|
||||
|
||||
entities.forEach(entity -> entitiesToSave.put(this.entityInformation.getRequiredId(entity), entity));
|
||||
Streamable.of(CollectionUtils.nullSafeIterable(entities)).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(entity -> entitiesToSave.put(entityInformation.getRequiredId(entity), entity));
|
||||
|
||||
this.template.putAll(entitiesToSave);
|
||||
if (!entitiesToSave.isEmpty()) {
|
||||
getTemplate().putAll(entitiesToSave);
|
||||
}
|
||||
|
||||
return entitiesToSave.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of entities stored in the {@link Region}.
|
||||
*
|
||||
* This method executes a {@literal SELECT count(*) FROM /Region} OQL query.
|
||||
*
|
||||
* @return a count of the number of entities stored in the {@link Region}.
|
||||
*/
|
||||
@Override
|
||||
public long count() {
|
||||
|
||||
String countQuery = String.format("SELECT count(*) FROM %s", this.template.getRegion().getFullPath());
|
||||
String regionPath = getRegion().getFullPath();
|
||||
String countQuery = String.format("SELECT count(*) FROM %s", regionPath);
|
||||
|
||||
SelectResults<Integer> results = this.template.find(countQuery);
|
||||
SelectResults<Integer> results = getTemplate().find(countQuery);
|
||||
|
||||
return Optional.ofNullable(results)
|
||||
.map(SelectResults::iterator)
|
||||
@@ -127,64 +205,104 @@ public class SimpleGemfireRepository<T, ID> implements GemfireRepository<T, ID>
|
||||
.orElse(0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an entity with the given ID is stored in the {@link Region}.
|
||||
*
|
||||
* @param id {@link Long} value identifying the entity.
|
||||
* @return a boolean value indicating whether an entity with the given ID is stored in the {@link Region}.
|
||||
* @see #findById(Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean existsById(ID id) {
|
||||
return findById(id).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> findById(ID id) {
|
||||
return Optional.ofNullable(this.template.get(id));
|
||||
public @NonNull Iterable<T> findAll() {
|
||||
|
||||
String regionPath = getRegion().getFullPath();
|
||||
String query = String.format("SELECT * FROM %s", regionPath);
|
||||
|
||||
SelectResults<T> selectResults = getTemplate().find(query);
|
||||
|
||||
return toList(selectResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> findAll() {
|
||||
|
||||
SelectResults<T> results =
|
||||
this.template.find(String.format("SELECT * FROM %s", this.template.getRegion().getFullPath()));
|
||||
|
||||
return results.asList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> findAll(Sort sort) {
|
||||
public @NonNull Iterable<T> findAll(@NonNull Sort sort) {
|
||||
|
||||
QueryString query = QueryString.of("SELECT * FROM /RegionPlaceholder")
|
||||
.fromRegion(this.entityInformation.getJavaType(), this.template.getRegion())
|
||||
.fromRegion(getEntityInformation().getJavaType(), getRegion())
|
||||
.orderBy(sort);
|
||||
|
||||
SelectResults<T> selectResults = this.template.find(query.toString());
|
||||
SelectResults<T> selectResults = getTemplate().find(query.toString());
|
||||
|
||||
return selectResults.asList();
|
||||
return toList(selectResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> findAllById(Iterable<ID> ids) {
|
||||
public @NonNull Iterable<T> findAllById(@NonNull Iterable<ID> ids) {
|
||||
|
||||
List<ID> keys = Streamable.of(ids).stream().collect(StreamUtils.toUnmodifiableList());
|
||||
List<ID> keys = Streamable.of(CollectionUtils.nullSafeIterable(ids)).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(StreamUtils.toUnmodifiableList());
|
||||
|
||||
return CollectionUtils.<ID, T>nullSafeMap(this.template.getAll(keys)).values().stream()
|
||||
.filter(Objects::nonNull).collect(Collectors.toList());
|
||||
Map<ID, T> keysValues = !keys.isEmpty()
|
||||
? getTemplate().getAll(keys)
|
||||
: Collections.emptyMap();
|
||||
|
||||
List<T> values = CollectionUtils.nullSafeMap(keysValues).values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(ID id) {
|
||||
this.template.remove(id);
|
||||
public Optional<T> findById(@NonNull ID id) {
|
||||
|
||||
T value = id != null
|
||||
? getTemplate().get(id)
|
||||
: null;
|
||||
|
||||
return Optional.ofNullable(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(T entity) {
|
||||
deleteById(this.entityInformation.getRequiredId(entity));
|
||||
public void delete(@NonNull T entity) {
|
||||
deleteById(getEntityInformation().getRequiredId(entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll(Iterable<? extends T> entities) {
|
||||
entities.forEach(this::delete);
|
||||
public void deleteAll() {
|
||||
|
||||
getTemplate().execute((GemfireCallback<Void>) region -> {
|
||||
|
||||
if (isPartitioned(region) || isTransactionPresent(region)) {
|
||||
doRegionClear(region);
|
||||
}
|
||||
else {
|
||||
SpringUtils.safeDoOperation(() -> region.clear(), () -> doRegionClear(region));
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll(@NonNull Iterable<? extends T> entities) {
|
||||
CollectionUtils.nullSafeIterable(entities).forEach(this::delete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(@NonNull ID id) {
|
||||
getTemplate().remove(id);
|
||||
}
|
||||
|
||||
boolean isPartitioned(Region<?, ?> region) {
|
||||
|
||||
return region != null && region.getAttributes() != null
|
||||
return region != null
|
||||
&& region.getAttributes() != null
|
||||
&& isPartitioned(region.getAttributes().getDataPolicy());
|
||||
}
|
||||
|
||||
@@ -206,23 +324,10 @@ public class SimpleGemfireRepository<T, ID> implements GemfireRepository<T, ID>
|
||||
region.removeAll(region.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
this.template.execute((GemfireCallback<Void>) region -> {
|
||||
@NonNull List<T> toList(@Nullable SelectResults<T> selectResults) {
|
||||
|
||||
if (isPartitioned(region) || isTransactionPresent(region)) {
|
||||
doRegionClear(region);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
region.clear();
|
||||
}
|
||||
catch (UnsupportedOperationException ignore) {
|
||||
doRegionClear(region);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
return selectResults != null
|
||||
? CollectionUtils.nullSafeList(selectResults.asList())
|
||||
: Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.repository.sample;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
@@ -23,7 +22,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Stuart Williams
|
||||
* @author John Blum
|
||||
*/
|
||||
public class Animal {
|
||||
public class Animal implements Identifiable<Long> {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
@@ -31,7 +30,7 @@ public class Animal {
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
@@ -39,7 +38,7 @@ public class Animal {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
@@ -48,7 +47,8 @@ public class Animal {
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == this) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -64,15 +64,18 @@ public class Animal {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
int hashValue = 17;
|
||||
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getId());
|
||||
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getName());
|
||||
|
||||
return hashValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{ @type = %1$s, id = %2$d, name = %3$s }", getClass().getSimpleName(), getId(), getName());
|
||||
return String.format("{ @type = %1$s, id = %2$d, name = %3$s }",
|
||||
getClass().getSimpleName(), getId(), getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*
|
||||
* https://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.sample;
|
||||
|
||||
/**
|
||||
* Defines a contract for Abstract Data Types (ADT) that can be identified.
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public interface Identifiable<T> {
|
||||
|
||||
T getId();
|
||||
|
||||
}
|
||||
@@ -13,27 +13,25 @@
|
||||
* 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 java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionEvent;
|
||||
import org.apache.geode.cache.query.SelectResults;
|
||||
import org.apache.geode.cache.util.CacheListenerAdapter;
|
||||
|
||||
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.data.gemfire.GemfireTemplate;
|
||||
@@ -48,11 +46,16 @@ import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link SimpleGemfireRepository}.
|
||||
* Integration Tests for {@link SimpleGemfireRepository}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.data.gemfire.GemfireTemplate
|
||||
* @see org.springframework.data.gemfire.LocalRegionFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication
|
||||
* @see org.springframework.data.gemfire.repository.support.SimpleGemfireRepository
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringRunner
|
||||
@@ -113,17 +116,17 @@ public class SimpleGemfireRepositoryIntegrationTests {
|
||||
this.template.put(carter.getId(), carter);
|
||||
this.template.put(leroi.getId(), leroi);
|
||||
|
||||
Collection<Person> result = this.repository.findAllById(Arrays.asList(carter.getId(), leroi.getId()));
|
||||
Iterable<Person> result = this.repository.findAllById(Arrays.asList(carter.getId(), leroi.getId()));
|
||||
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.size()).isEqualTo(2);
|
||||
assertThat(result).hasSize(2);
|
||||
assertThat(result).containsAll(Arrays.asList(carter, leroi));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAllWithIdsReturnsNoMatches() {
|
||||
|
||||
Collection<Person> results = this.repository.findAllById(Arrays.asList(1L, 2L));
|
||||
Iterable<Person> results = this.repository.findAllById(Arrays.asList(1L, 2L));
|
||||
|
||||
assertThat(results).isNotNull();
|
||||
assertThat(results).isEmpty();
|
||||
@@ -139,7 +142,7 @@ public class SimpleGemfireRepositoryIntegrationTests {
|
||||
this.template.put(kurt.getId(), kurt);
|
||||
this.template.put(eddie.getId(), eddie);
|
||||
|
||||
Collection<Person> results = this.repository.findAllById(Arrays.asList(0L, 1L, 2L, 4L));
|
||||
Iterable<Person> results = this.repository.findAllById(Arrays.asList(0L, 1L, 2L, 4L));
|
||||
|
||||
assertThat(results).isNotNull();
|
||||
assertThat(results).hasSize(2);
|
||||
|
||||
@@ -17,6 +17,8 @@ package org.springframework.data.gemfire.repository.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
@@ -35,6 +37,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -54,11 +57,15 @@ import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.apache.geode.cache.query.SelectResults;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
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.repository.sample.Identifiable;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link SimpleGemfireRepository}.
|
||||
*
|
||||
@@ -75,10 +82,12 @@ import org.springframework.data.repository.core.EntityInformation;
|
||||
* @see org.springframework.data.repository.core.EntityInformation
|
||||
* @since 1.4.5
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class SimpleGemfireRepositoryUnitTests {
|
||||
|
||||
protected Map<Long, Animal> asMap(Iterable<Animal> animals) {
|
||||
private final AtomicLong idSequence = new AtomicLong(0L);
|
||||
|
||||
private Map<Long, Animal> asMap(Iterable<Animal> animals) {
|
||||
|
||||
Map<Long, Animal> animalMap = new HashMap<>();
|
||||
|
||||
@@ -89,16 +98,17 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
return animalMap;
|
||||
}
|
||||
|
||||
protected Animal newAnimal(String name) {
|
||||
private Animal newAnimal(String name) {
|
||||
|
||||
Animal animal = new Animal();
|
||||
|
||||
animal.setId(this.idSequence.incrementAndGet());
|
||||
animal.setName(name);
|
||||
|
||||
return animal;
|
||||
}
|
||||
|
||||
protected Animal newAnimal(Long id, String name) {
|
||||
private Animal newAnimal(Long id, String name) {
|
||||
|
||||
Animal animal = newAnimal(name);
|
||||
|
||||
@@ -107,11 +117,15 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
return animal;
|
||||
}
|
||||
|
||||
protected GemfireTemplate newGemfireTemplate(Region<?, ?> region) {
|
||||
private GemfireTemplate newGemfireTemplate(Region<?, ?> region) {
|
||||
return new GemfireTemplate(region);
|
||||
}
|
||||
|
||||
protected Cache mockCache(String name, boolean transactionExists) {
|
||||
private <ID, T extends Identifiable<ID>> Wrapper<T, ID> newWrapper(T entity) {
|
||||
return new Wrapper<>(entity, entity.getId());
|
||||
}
|
||||
|
||||
private Cache mockCache(String name, boolean transactionExists) {
|
||||
|
||||
Cache mockCache = mock(Cache.class, String.format("%s.MockCache", name));
|
||||
|
||||
@@ -124,7 +138,7 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
return mockCache;
|
||||
}
|
||||
|
||||
protected EntityInformation<Animal, Long> mockEntityInformation() {
|
||||
private EntityInformation<Animal, Long> mockEntityInformation() {
|
||||
|
||||
EntityInformation<Animal, Long> mockEntityInformation = mock(EntityInformation.class);
|
||||
|
||||
@@ -149,11 +163,11 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
return mockEntityInformation;
|
||||
}
|
||||
|
||||
protected Region mockRegion() {
|
||||
private Region mockRegion() {
|
||||
return mockRegion("MockRegion");
|
||||
}
|
||||
|
||||
protected Region mockRegion(String name) {
|
||||
private Region mockRegion(String name) {
|
||||
|
||||
Region mockRegion = mock(Region.class, String.format("%s.MockRegion", name));
|
||||
|
||||
@@ -163,7 +177,7 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
return mockRegion;
|
||||
}
|
||||
|
||||
protected Region mockRegion(String name, Cache mockCache, DataPolicy dataPolicy) {
|
||||
private Region mockRegion(String name, Cache mockCache, DataPolicy dataPolicy) {
|
||||
|
||||
Region mockRegion = mockRegion(name);
|
||||
|
||||
@@ -179,17 +193,20 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructsSimpleGemfireRepositorySuccessfully() {
|
||||
public void constructSimpleGemfireRepositorySuccessfully() {
|
||||
|
||||
Region mockRegion = mock(Region.class);
|
||||
Region mockRegion = mockRegion();
|
||||
|
||||
GemfireTemplate template = spy(new GemfireTemplate(mockRegion));
|
||||
GemfireTemplate template = spy(newGemfireTemplate(mockRegion));
|
||||
|
||||
EntityInformation mockEntityInformation = mock(EntityInformation.class);
|
||||
EntityInformation mockEntityInformation = mockEntityInformation();
|
||||
|
||||
SimpleGemfireRepository repository = new SimpleGemfireRepository(template, mockEntityInformation);
|
||||
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(repository.getEntityInformation()).isEqualTo(mockEntityInformation);
|
||||
assertThat(repository.getLogger()).isNotNull();
|
||||
assertThat(repository.getTemplate()).isEqualTo(template);
|
||||
|
||||
verifyNoInteractions(template, mockRegion, mockEntityInformation);
|
||||
}
|
||||
@@ -225,29 +242,63 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveEntityIsCorrect() {
|
||||
public void getRegionFromTemplate() {
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
GemfireTemplate template = spy(newGemfireTemplate(mockRegion));
|
||||
|
||||
EntityInformation<Animal, Long> mockEntityInformation = mockEntityInformation();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(template, mockEntityInformation);
|
||||
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(repository.getTemplate()).isEqualTo(template);
|
||||
assertThat(repository.getRegion()).isEqualTo(mockRegion);
|
||||
|
||||
verify(template, times(1)).getRegion();
|
||||
verifyNoInteractions(mockRegion, mockEntityInformation);
|
||||
verifyNoMoreInteractions(template);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveEntitySuccessfully() {
|
||||
|
||||
Animal cat = newAnimal(1L, "cat");
|
||||
|
||||
Logger mockLogger = mock(Logger.class);
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
spy(new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation()));
|
||||
|
||||
Animal dog = repository.save(newAnimal("dog"));
|
||||
doReturn(mockLogger).when(repository).getLogger();
|
||||
doReturn(true).when(mockLogger).isDebugEnabled();
|
||||
doReturn(cat).when(mockRegion).put(anyLong(), any());
|
||||
|
||||
Animal dog = repository.save(newAnimal(1L, "dog"));
|
||||
|
||||
assertThat(dog).isNotNull();
|
||||
assertThat(dog.getId().longValue()).isEqualTo(1L);
|
||||
assertThat(dog.getName()).isEqualTo("dog");
|
||||
|
||||
verify(mockLogger, times(1)).isDebugEnabled();
|
||||
verify(mockLogger, times(1))
|
||||
.debug(eq("Overwrote existing value [{}] for ID [{}]"), eq(cat), eq(1L));
|
||||
verify(mockRegion, times(1)).put(eq(1L), eq(dog));
|
||||
verifyNoMoreInteractions(mockLogger, mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveEntitiesIsCorrect() {
|
||||
public void saveEntitiesSuccessfully() {
|
||||
|
||||
List<Animal> animals = new ArrayList<>(3);
|
||||
|
||||
animals.add(newAnimal("bird"));
|
||||
animals.add(newAnimal("cat"));
|
||||
animals.add(newAnimal("dog"));
|
||||
animals.add(newAnimal(1L, "bird"));
|
||||
animals.add(newAnimal(2L, "cat"));
|
||||
animals.add(newAnimal(3L, "dog"));
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
@@ -257,24 +308,82 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
Iterable<Animal> savedAnimals = repository.saveAll(animals);
|
||||
|
||||
assertThat(savedAnimals).isNotNull();
|
||||
assertThat(savedAnimals).isNotSameAs(animals);
|
||||
assertThat(savedAnimals).containsAll(animals);
|
||||
|
||||
verify(mockRegion, times(1)).putAll(eq(asMap(savedAnimals)));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveWrapperIsCorrect() {
|
||||
Animal dog = newAnimal(1L, "dog");
|
||||
public void saveWrapperSuccessfully() {
|
||||
|
||||
Wrapper dogWrapper = new Wrapper(dog, dog.getId());
|
||||
Animal dog = newAnimal(2L, "dog");
|
||||
|
||||
Logger mockLogger = mock(Logger.class);
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
spy(new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation()));
|
||||
|
||||
doReturn(mockLogger).when(repository).getLogger();
|
||||
doReturn(true).when(mockLogger).isDebugEnabled();
|
||||
doReturn(dog).when(mockRegion).put(anyLong(), any());
|
||||
|
||||
Animal cat = repository.save(newWrapper(newAnimal(2L, "cat")));
|
||||
|
||||
assertThat(cat).isNotNull();
|
||||
assertThat(cat.getId()).isEqualTo(2L);
|
||||
assertThat(cat.getName()).isEqualTo("cat");
|
||||
|
||||
verify(mockLogger, times(1)).isDebugEnabled();
|
||||
verify(mockLogger, times(1))
|
||||
.debug(eq("Overwrote existing value [{}] for ID [{}]"), eq(dog), eq(2L));
|
||||
verify(mockRegion, times(1)).put(eq(2L), eq(cat));
|
||||
verifyNoMoreInteractions(mockLogger, mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveAllEntitiesWithIterableContainingNullEntitiesIsNullSafe() {
|
||||
|
||||
List<Animal> animals = new ArrayList<>();
|
||||
|
||||
animals.add(newAnimal(1L, "cat"));
|
||||
animals.add(null);
|
||||
animals.add(newAnimal(2L, "dog"));
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
assertThat(repository.save(dogWrapper)).isEqualTo(dog);
|
||||
Iterable<Animal> savedAnimals = repository.saveAll(animals);
|
||||
|
||||
verify(mockRegion, times(1)).put(eq(dog.getId()), eq(dog));
|
||||
assertThat(savedAnimals).isNotNull();
|
||||
assertThat(savedAnimals).isNotSameAs(animals);
|
||||
assertThat(savedAnimals).hasSize(2);
|
||||
assertThat(savedAnimals).containsAll(Arrays.asList(animals.get(0), animals.get(2)));
|
||||
|
||||
verify(mockRegion, times(1))
|
||||
.putAll(eq(asMap(Arrays.asList(animals.get(0), animals.get(2)))));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveAllEntitiesWithNullIterableIsNullSafe() {
|
||||
|
||||
Region<Long, Animal> mockRegion = mock(Region.class);
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
Iterable<?> iterable = repository.saveAll(null);
|
||||
|
||||
assertThat(iterable).isNotNull();
|
||||
assertThat(iterable).isEmpty();
|
||||
|
||||
verifyNoInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -287,7 +396,7 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
GemfireTemplate template = spy(newGemfireTemplate(mockRegion));
|
||||
|
||||
doReturn(mockSelectResults).when(template).find(eq("SELECT count(*) FROM /Example"));
|
||||
when(mockSelectResults.iterator()).thenReturn(Collections.singletonList(21).iterator());
|
||||
doReturn(Collections.singletonList(21).iterator()).when(mockSelectResults).iterator();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(template, mockEntityInformation());
|
||||
@@ -309,7 +418,7 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
|
||||
GemfireTemplate template = spy(newGemfireTemplate(mockRegion));
|
||||
|
||||
doReturn(null).when(template).find(eq("SELECT count(*) FROM /Example"));
|
||||
doReturn(null).when(template).find(anyString());
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(template, mockEntityInformation());
|
||||
@@ -332,7 +441,7 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
|
||||
GemfireTemplate template = spy(newGemfireTemplate(mockRegion));
|
||||
|
||||
doReturn(mockSelectResults).when(template).find(eq("SELECT count(*) FROM /Example"));
|
||||
doReturn(mockSelectResults).when(template).find(anyString());
|
||||
doReturn(null).when(mockSelectResults).iterator();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
@@ -357,7 +466,7 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
|
||||
GemfireTemplate template = spy(newGemfireTemplate(mockRegion));
|
||||
|
||||
doReturn(mockSelectResults).when(template).find(eq("SELECT count(*) FROM /Example"));
|
||||
doReturn(mockSelectResults).when(template).find(anyString());
|
||||
doReturn(Collections.emptyIterator()).when(mockSelectResults).iterator();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
@@ -374,123 +483,263 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void existsIsCorrect() {
|
||||
public void countWhenSelectResultsIteratorContainsNullIsNullSafeReturnsZero() {
|
||||
|
||||
SelectResults mockSelectResults = mock(SelectResults.class);
|
||||
|
||||
Region mockRegion = mockRegion("Example");
|
||||
|
||||
Iterator mockIterator = mock(Iterator.class);
|
||||
|
||||
GemfireTemplate template = spy(newGemfireTemplate(mockRegion));
|
||||
|
||||
doReturn(mockSelectResults).when(template).find(anyString());
|
||||
doReturn(mockIterator).when(mockSelectResults).iterator();
|
||||
doReturn(true).when(mockIterator).hasNext();
|
||||
doReturn(null).when(mockIterator).next();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(template, mockEntityInformation());
|
||||
|
||||
assertThat(repository).isNotNull();
|
||||
assertThat(repository.count()).isEqualTo(0L);
|
||||
|
||||
verify(template, times(1)).getRegion();
|
||||
verify(mockRegion, times(1)).getFullPath();
|
||||
verify(template, times(1)).find(eq("SELECT count(*) FROM /Example"));
|
||||
verify(mockSelectResults, times(1)).iterator();
|
||||
verify(mockIterator, times(1)).hasNext();
|
||||
verify(mockIterator, times(1)).next();
|
||||
verifyNoMoreInteractions(mockIterator, mockRegion, mockSelectResults, template);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void existsByIdCallsFindById() {
|
||||
|
||||
Animal dog = newAnimal(1L, "dog");
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
when(mockRegion.get(any(Long.class))).then(
|
||||
invocation -> (dog.getId().equals(invocation.getArguments()[0]) ? dog : null));
|
||||
doAnswer(invocation -> dog.getId().equals(invocation.getArgument(0)) ? dog : null)
|
||||
.when(mockRegion).get(anyLong());
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
spy(new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation()));
|
||||
|
||||
assertThat(repository.existsById(1L)).isTrue();
|
||||
assertThat(repository.existsById(2L)).isFalse();
|
||||
assertThat(repository.existsById(10L)).isFalse();
|
||||
|
||||
verify(repository, times(1)).findById(eq(1L));
|
||||
verify(mockRegion, times(1)).get(eq(1L));
|
||||
verify(repository, times(1)).findById(eq(2L));
|
||||
verify(mockRegion, times(1)).get(eq(2L));
|
||||
verify(repository, times(1)).findById(eq(10L));
|
||||
verify(mockRegion, times(1)).get(eq(10L));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneIsCorrect() {
|
||||
Animal dog = newAnimal(1L, "dog");
|
||||
public void findAllSuccessfully() {
|
||||
|
||||
GemfireTemplate mockTemplate = mock(GemfireTemplate.class);
|
||||
|
||||
List<Object> results = Arrays.asList("test", "mock", "fake");
|
||||
|
||||
Region mockRegion = mockRegion("Example");
|
||||
|
||||
SelectResults mockSelectResults = mock(SelectResults.class);
|
||||
|
||||
doReturn(mockRegion).when(mockTemplate).getRegion();
|
||||
doReturn(mockSelectResults).when(mockTemplate).find(anyString());
|
||||
doReturn(results).when(mockSelectResults).asList();
|
||||
|
||||
SimpleGemfireRepository repository = new SimpleGemfireRepository(mockTemplate, mockEntityInformation());
|
||||
|
||||
Iterable<Object> returnValue = repository.findAll();
|
||||
|
||||
assertThat(returnValue).isNotNull();
|
||||
assertThat(returnValue).containsAll(results);
|
||||
|
||||
verify(mockTemplate, times(1)).getRegion();
|
||||
verify(mockRegion, times(1)).getFullPath();
|
||||
verify(mockTemplate, times(1)).find(eq("SELECT * FROM /Example"));
|
||||
verify(mockSelectResults, times(1)).asList();
|
||||
verifyNoMoreInteractions(mockRegion, mockSelectResults, mockTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAllOrderedBySortSuccessfully() {
|
||||
|
||||
GemfireTemplate mockTemplate = mock(GemfireTemplate.class);
|
||||
|
||||
List<Object> results = Arrays.asList("test", "mock", "fake");
|
||||
|
||||
Region mockRegion = mockRegion("Example");
|
||||
|
||||
SelectResults mockSelectResults = mock(SelectResults.class);
|
||||
|
||||
doReturn(mockRegion).when(mockTemplate).getRegion();
|
||||
doReturn(mockSelectResults).when(mockTemplate).find(anyString());
|
||||
doReturn(results).when(mockSelectResults).asList();
|
||||
|
||||
SimpleGemfireRepository repository = new SimpleGemfireRepository(mockTemplate, mockEntityInformation());
|
||||
|
||||
Iterable<Object> returnValue = repository.findAll(Sort.by(Sort.Order.asc("name"), Sort.Order.desc("birthDate")));
|
||||
|
||||
assertThat(returnValue).isNotNull();
|
||||
assertThat(returnValue).containsAll(results);
|
||||
|
||||
verify(mockTemplate, times(1)).getRegion();
|
||||
verify(mockRegion, times(1)).getFullPath();
|
||||
verify(mockTemplate, times(1))
|
||||
.find(eq("SELECT DISTINCT * FROM /Example ORDER BY name ASC, birthDate DESC"));
|
||||
verify(mockSelectResults, times(1)).asList();
|
||||
verifyNoMoreInteractions(mockRegion, mockSelectResults, mockTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAllByIdSuccessfully() {
|
||||
|
||||
Map<Long, Animal> animals = Stream.of(
|
||||
newAnimal(1L, "bird"),
|
||||
newAnimal(2L, "cat"),
|
||||
newAnimal(3L, "dog")
|
||||
).collect(Collectors.toMap(Animal::getId, Function.identity()));
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
when(mockRegion.get(any(Long.class))).then(
|
||||
invocation -> (dog.getId().equals(invocation.getArguments()[0]) ? dog : null));
|
||||
doAnswer(invocation -> {
|
||||
|
||||
Collection<Long> keys = invocation.getArgument(0);
|
||||
|
||||
return animals.values().stream()
|
||||
.filter((animal -> keys.contains(animal.getId())))
|
||||
.collect(Collectors.toMap(Animal::getId, Function.identity()));
|
||||
|
||||
}).when(mockRegion).getAll(any(Collection.class));
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
assertThat(repository.findById(1L).orElse(null)).isEqualTo(dog);
|
||||
assertThat(repository.findById(10L).isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAllIsCorrect() {
|
||||
Map<Long, Animal> animals =
|
||||
Stream.of(newAnimal(1L, "bird"), newAnimal(2L, "cat"), newAnimal(3L, "dog"))
|
||||
.collect(Collectors.toMap(Animal::getId, Function.identity()));
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
when(mockRegion.getAll(any(Collection.class))).then(invocation -> {
|
||||
Collection<Long> keys = invocation.getArgument(0);
|
||||
|
||||
return animals.values().stream().filter((animal -> keys.contains(animal.getId())))
|
||||
.collect(Collectors.toMap(Animal::getId, Function.identity()));
|
||||
});
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository = new SimpleGemfireRepository<>(
|
||||
newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
Collection<Animal> animalsFound = repository.findAllById(Arrays.asList(1L, 3L));
|
||||
Iterable<Animal> animalsFound = repository.findAllById(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)));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAllWithIdsReturnsNoMatches() {
|
||||
public void findAllByIdReturnsNoMatches() {
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
when(mockRegion.getAll(any(Collection.class))).then(invocation -> {
|
||||
Collection<Long> keys = invocation.getArgument(0);
|
||||
Map<Long, Animal> result = new HashMap<>(keys.size());
|
||||
|
||||
for (Long key : keys) {
|
||||
result.put(key, null);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
doReturn(Collections.emptyMap()).when(mockRegion).getAll(any(Collection.class));
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
Collection<Animal> animalsFound = repository.findAllById(Arrays.asList(1L, 2L, 3L));
|
||||
Iterable<Animal> animalsFound = repository.findAllById(Arrays.asList(1L, null, 2L, null, 3L));
|
||||
|
||||
assertThat(animalsFound).isNotNull();
|
||||
assertThat(animalsFound).isEmpty();
|
||||
|
||||
verify(mockRegion, times(1)).getAll(eq(Arrays.asList(1L, 2L, 3L)));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAllWithIdsReturnsPartialMatches() {
|
||||
Map<Long, Animal> animals =
|
||||
Stream.of(newAnimal(1L, "bird"), newAnimal(2L, "cat"), newAnimal(3L, "dog"))
|
||||
.collect(Collectors.toMap(Animal::getId, Function.identity()));
|
||||
public void findAllByIdReturnsPartialMatches() {
|
||||
|
||||
Map<Long, Animal> animals = Stream.of(
|
||||
newAnimal(1L, "bird"),
|
||||
newAnimal(2L, "cat"),
|
||||
newAnimal(3L, "dog")
|
||||
).collect(Collectors.toMap(Animal::getId, Function.identity()));
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
when(mockRegion.getAll(any(Collection.class))).then(invocation -> {
|
||||
doAnswer(invocation -> {
|
||||
|
||||
Collection<Long> keys = invocation.getArgument(0);
|
||||
Map<Long, Animal> result = new HashMap<>(keys.size());
|
||||
|
||||
for (Long key : keys) {
|
||||
result.put(key, animals.get(key));
|
||||
}
|
||||
return keys.stream()
|
||||
.filter(animals::containsKey)
|
||||
.collect(Collectors.toMap(Function.identity(), animals::get));
|
||||
|
||||
return result;
|
||||
});
|
||||
}).when(mockRegion).getAll(any(Collection.class));
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
Collection<Animal> animalsFound = repository.findAllById(Arrays.asList(0L, 1L, 2L, 4L));
|
||||
Iterable<Animal> animalsFound = repository.findAllById(Arrays.asList(null, 0L, null, 1L, 2L, 4L, null));
|
||||
|
||||
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)));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteByIdIsCorrect() {
|
||||
public void findAllByIdWithNullIterableIsNullSafe() {
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
Iterable<Animal> animals = repository.findAllById(null);
|
||||
|
||||
assertThat(animals).isNotNull();
|
||||
assertThat(animals).isEmpty();
|
||||
|
||||
verifyNoInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByIdSuccessfully() {
|
||||
|
||||
Animal dog = newAnimal(1L, "dog");
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
doAnswer(invocation -> dog.getId().equals(invocation.getArgument(0)) ? dog : null)
|
||||
.when(mockRegion).get(any(Long.class));
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
assertThat(repository.findById(1L).orElse(null)).isEqualTo(dog);
|
||||
assertThat(repository.findById(2L).isPresent()).isFalse();
|
||||
assertThat(repository.findById(10L).isPresent()).isFalse();
|
||||
|
||||
verify(mockRegion, times(1)).get(eq(1L));
|
||||
verify(mockRegion, times(1)).get(eq(2L));
|
||||
verify(mockRegion, times(1)).get(eq(10L));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByIdWithNullIdIsNullSafe() {
|
||||
|
||||
Region mockRegion = mockRegion();
|
||||
|
||||
SimpleGemfireRepository repository =
|
||||
new SimpleGemfireRepository(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
assertThat(repository.findById(null).isPresent()).isFalse();
|
||||
|
||||
verifyNoInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteByIdSuccessfully() {
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
@@ -499,37 +748,47 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
repository.deleteById(1L);
|
||||
|
||||
verify(mockRegion, times(1)).remove(eq(1L));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteEntityIsCorrect() {
|
||||
public void deleteEntitySuccessfully() {
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
spy(new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation()));
|
||||
|
||||
repository.delete(newAnimal(1L, "dog"));
|
||||
|
||||
verify(repository, times(1)).deleteById(eq(1L));
|
||||
verify(mockRegion, times(1)).remove(eq(1L));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteEntitiesIsCorrect() {
|
||||
public void deleteEntitiesSuccessfully() {
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion();
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository =
|
||||
new SimpleGemfireRepository<>(newGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
repository.deleteAll(Arrays.asList(newAnimal(1L, "bird"), newAnimal(2L, "cat"),
|
||||
newAnimal(3L, "dog")));
|
||||
repository.deleteAll(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));
|
||||
verifyNoMoreInteractions(mockRegion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteAllWithClear() {
|
||||
|
||||
Cache mockCache = mockCache("MockCache", false);
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion("MockRegion", mockCache, DataPolicy.REPLICATE);
|
||||
@@ -547,6 +806,7 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
|
||||
@Test
|
||||
public void deleteAllWithKeysWhenClearThrowsException() {
|
||||
|
||||
Cache mockCache = mockCache("MockCache", false);
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion("MockRegion", mockCache, DataPolicy.PERSISTENT_REPLICATE);
|
||||
@@ -570,6 +830,7 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
|
||||
@Test
|
||||
public void deleteAllWithKeysWhenPartitionRegion() {
|
||||
|
||||
Cache mockCache = mockCache("MockCache", false);
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion("MockRegion", mockCache, DataPolicy.PERSISTENT_PARTITION);
|
||||
@@ -592,6 +853,7 @@ public class SimpleGemfireRepositoryUnitTests {
|
||||
|
||||
@Test
|
||||
public void deleteAllWithKeysWhenTransactionPresent() {
|
||||
|
||||
Cache mockCache = mockCache("MockCache", true);
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion("MockRegion", mockCache, DataPolicy.REPLICATE);
|
||||
|
||||
Reference in New Issue
Block a user