SGF-354 - SimpleGemfireRepository.deleteAll that supports transactions.
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.assertTrue;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.repository.GemfireRepository;
|
||||
import org.springframework.data.gemfire.repository.sample.Customer;
|
||||
import org.springframework.data.repository.core.support.ReflectionEntityInformation;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* The SimpleGemfireRepositoryTransactionalIntegrationTest class is a test suite of test cases testing
|
||||
* the SimpleGemfireRepository class and SDC Repository abstraction implementation in the context of
|
||||
* GemFire "Cache" Transactions.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.junit.runner.RunWith
|
||||
* @see org.springframework.data.gemfire.repository.support.SimpleGemfireRepository
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
|
||||
* @since 1.6.0
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@SuppressWarnings("unused")
|
||||
public class SimpleGemfireRepositoryTransactionalIntegrationTest {
|
||||
|
||||
// TODO add additional test cases for SimpleGemfireRepository (Region operations) in the presence of Transactions!!!
|
||||
|
||||
protected static final AtomicLong ID_SEQUENCE = new AtomicLong(0l);
|
||||
|
||||
@Autowired
|
||||
private CustomerService customerService;
|
||||
|
||||
@Resource(name = "Customers")
|
||||
private Region customers;
|
||||
|
||||
protected static Customer createCustomer(final String firstName, final String lastName) {
|
||||
Customer customer = new SerializableCustomer(firstName, lastName);
|
||||
customer.setId(ID_SEQUENCE.incrementAndGet());
|
||||
return customer;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
assertNotNull("The 'Customers' GemFire Cache Region was not properly configured and initialized!", customers);
|
||||
assertEquals("Customers", customers.getName());
|
||||
assertEquals("/Customers", customers.getFullPath());
|
||||
assertTrue(customers.isEmpty());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
customers.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAll() {
|
||||
Collection<Customer> expectedCustomers = new ArrayList<Customer>(4);
|
||||
|
||||
expectedCustomers.add(createCustomer("Jon", "Doe"));
|
||||
expectedCustomers.add(createCustomer("Jane", "Doe"));
|
||||
expectedCustomers.add(createCustomer("Pie", "Doe"));
|
||||
expectedCustomers.add(createCustomer("Cookie", "Doe"));
|
||||
|
||||
customerService.saveAll(expectedCustomers);
|
||||
|
||||
assertFalse(customers.isEmpty());
|
||||
assertEquals(expectedCustomers.size(), customers.size());
|
||||
|
||||
try {
|
||||
customerService.removeAllCausingTransactionRollback();
|
||||
}
|
||||
catch (RuntimeException ignore) {
|
||||
// the RuntimeException should cause the Cache Transaction to rollback and avoid the Region modification!
|
||||
}
|
||||
|
||||
assertFalse(customers.isEmpty());
|
||||
assertEquals(expectedCustomers.size(), customers.size());
|
||||
|
||||
customerService.removeAll();
|
||||
|
||||
assertTrue(customers.isEmpty());
|
||||
}
|
||||
|
||||
public static class SerializableCustomer extends Customer implements Serializable {
|
||||
|
||||
public SerializableCustomer() {
|
||||
}
|
||||
|
||||
public SerializableCustomer(final Long id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public SerializableCustomer(final String firstName, final String lastName) {
|
||||
super(firstName, lastName);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomerService {
|
||||
|
||||
private GemfireRepository<Customer, Long> customerRepository;
|
||||
|
||||
private TransactionTemplate transactionTemplate;
|
||||
|
||||
@Autowired
|
||||
public CustomerService(GemfireTemplate customersTemplate, PlatformTransactionManager transactionManager) {
|
||||
customerRepository = new SimpleGemfireRepository<Customer, Long>(customersTemplate,
|
||||
new ReflectionEntityInformation<Customer, Long>(Customer.class));
|
||||
|
||||
transactionTemplate = new TransactionTemplate(transactionManager);
|
||||
}
|
||||
|
||||
public void saveAll(final Iterable<Customer> customers) {
|
||||
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override protected void doInTransactionWithoutResult(final TransactionStatus status) {
|
||||
customerRepository.save(customers);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeAllCausingTransactionRollback() {
|
||||
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override protected void doInTransactionWithoutResult(final TransactionStatus status) {
|
||||
removeAll();
|
||||
throw new IllegalStateException("'removeAll' operation not permitted");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeAll() {
|
||||
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override protected void doInTransactionWithoutResult(final TransactionStatus status) {
|
||||
customerRepository.deleteAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -48,7 +48,11 @@ import org.springframework.data.gemfire.repository.sample.Animal;
|
||||
import org.springframework.data.gemfire.test.support.CollectionUtils;
|
||||
import org.springframework.data.repository.core.EntityInformation;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.CacheTransactionManager;
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
|
||||
/**
|
||||
* The SimpleGemfireRepositoryUnitTest class is a test suite of test cases testing the contract and functionality
|
||||
@@ -57,6 +61,8 @@ import com.gemstone.gemfire.cache.Region;
|
||||
* @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
|
||||
*/
|
||||
@@ -87,6 +93,18 @@ public class SimpleGemfireRepositoryUnitTest {
|
||||
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<Animal, Long> mockEntityInformation() {
|
||||
EntityInformation<Animal, Long> mockEntityInformation = mock(EntityInformation.class);
|
||||
|
||||
@@ -105,6 +123,20 @@ public class SimpleGemfireRepositoryUnitTest {
|
||||
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<Long, Animal> mockRegion = mock(Region.class, "testSave");
|
||||
@@ -272,32 +304,89 @@ public class SimpleGemfireRepositoryUnitTest {
|
||||
|
||||
@Test
|
||||
public void testDeleteAllWithClear() {
|
||||
Region<Long, Animal> mockRegion = mock(Region.class, "testDeleteEntities");
|
||||
Cache mockCache = mockCache("testDeleteAllWithClear", false);
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository = new SimpleGemfireRepository<Animal, Long>(
|
||||
Region<Long, Animal> mockRegion = mockRegion("testDeleteAllWithClear", mockCache, DataPolicy.REPLICATE);
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> gemfireRepository = new SimpleGemfireRepository<Animal, Long>(
|
||||
createGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
repository.deleteAll();
|
||||
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 testDeleteAllWithKeys() {
|
||||
Region<Long, Animal> mockRegion = mock(Region.class, "testDeleteEntities");
|
||||
public void testDeleteAllWithKeysWhenClearThrowsUnsupportedOperationException() {
|
||||
Cache mockCache = mockCache("testDeleteAllWithKeysWhenClearThrowsUnsupportedOperationException", false);
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion("testDeleteAllWithKeysWhenClearThrowsUnsupportedOperationException",
|
||||
mockCache, DataPolicy.PERSISTENT_REPLICATE);
|
||||
|
||||
doThrow(new UnsupportedOperationException("Not Implemented!")).when(mockRegion).clear();
|
||||
when(mockRegion.keySet()).thenReturn(new HashSet<Long>(Arrays.asList(1l, 2l, 3l)));
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> repository = new SimpleGemfireRepository<Animal, Long>(
|
||||
SimpleGemfireRepository<Animal, Long> gemfireRepository = new SimpleGemfireRepository<Animal, Long>(
|
||||
createGemfireTemplate(mockRegion), mockEntityInformation());
|
||||
|
||||
repository.deleteAll();
|
||||
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)).remove(eq(1l));
|
||||
verify(mockRegion, times(1)).remove(eq(2l));
|
||||
verify(mockRegion, times(1)).remove(eq(3l));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAllWithKeysWhenPartitionRegion() {
|
||||
Cache mockCache = mockCache("testDeleteAllWithKeysWhenPartitionRegion", false);
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion("testDeleteAllWithKeysWhenPartitionRegion", mockCache,
|
||||
DataPolicy.PERSISTENT_PARTITION);
|
||||
|
||||
when(mockRegion.keySet()).thenReturn(new HashSet<Long>(Arrays.asList(1l, 2l, 3l)));
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> gemfireRepository = new SimpleGemfireRepository<Animal, Long>(
|
||||
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)).remove(eq(1l));
|
||||
verify(mockRegion, times(1)).remove(eq(2l));
|
||||
verify(mockRegion, times(1)).remove(eq(3l));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAllWithKeysWhenTransactionPresent() {
|
||||
Cache mockCache = mockCache("testDeleteAllWithKeysWhenTransactionPresent", true);
|
||||
|
||||
Region<Long, Animal> mockRegion = mockRegion("testDeleteAllWithKeysWhenTransactionPresent", mockCache,
|
||||
DataPolicy.REPLICATE);
|
||||
|
||||
when(mockRegion.keySet()).thenReturn(new HashSet<Long>(Arrays.asList(1l, 2l, 3l)));
|
||||
|
||||
SimpleGemfireRepository<Animal, Long> gemfireRepository = new SimpleGemfireRepository<Animal, Long>(
|
||||
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)).remove(eq(1l));
|
||||
verify(mockRegion, times(1)).remove(eq(2l));
|
||||
verify(mockRegion, times(1)).remove(eq(3l));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user