package com.smartitengineering.cms.repo.dao.impl.tx; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.smartitengineering.cms.repo.dao.impl.AbstractRepositoryDomain; import com.smartitengineering.cms.repo.dao.tx.TransactionException; import com.smartitengineering.dao.common.CommonReadDao; import com.smartitengineering.dao.common.CommonWriteDao; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.atomic.AtomicLong; import junit.framework.Assert; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.Sequence; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author imyousuf */ public class TransactionServiceImplTest { private Injector injector; private Mockery mockery; private TransactionInMemoryCache mockMemCache; private TransactionFactory mockFactory; private static final Logger LOGGER = LoggerFactory.getLogger(TransactionServiceImplTest.class); @Before public void setup() { mockery = new Mockery(); mockFactory = mockery.mock(TransactionFactory.class); mockMemCache = mockery.mock(TransactionInMemoryCache.class); injector = Guice.createInjector(new AbstractModule() { @Override protected void configure() { bind(TransactionFactory.class).toInstance(mockFactory); bind(TransactionInMemoryCache.class).toInstance(mockMemCache); bind(TransactionService.class).to(TransactionServiceImpl.class); } }); } @Test public void testAtomicLongIncrementForMaxValue() { Assert.assertEquals(Long.MIN_VALUE, new AtomicLong(Long.MAX_VALUE).incrementAndGet()); } @Test public void testConcurrentIdGeneration() { final TransactionService service = injector.getInstance(TransactionService.class); final Set<String> txIds = new ConcurrentSkipListSet<String>(); final int threadCount = 10; final int loopCount = 100000; List<Thread> threads = new ArrayList<Thread>(); long start = System.currentTimeMillis(); for (int i = 0; i < threadCount; ++i) { Thread thread = new Thread(new Runnable() { public void run() { for (int j = 0; j < loopCount; ++j) { txIds.add(service.getNextTransactionId()); } } }); thread.start(); threads.add(thread); } for (Thread thread : threads) { try { thread.join(); } catch (Exception ex) { LOGGER.error("Error waiting for a thread", ex); } } long end = System.currentTimeMillis(); Assert.assertEquals((threadCount * loopCount), txIds.size()); System.out.println("Time taken to generate " + (threadCount * loopCount) + " ids is " + (end - start)); } @Test(expected = IllegalStateException.class) public void testTransitionFromSaveToSave() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.getActualStateAfterTransition(OpState.SAVE, OpState.SAVE); } @Test public void testTransitionFromSaveToUpdate() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; Assert.assertEquals(OpState.SAVE, serviceImpl.getActualStateAfterTransition(OpState.SAVE, OpState.UPDATE)); } @Test public void testTransitionFromSaveToDelete() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; Assert.assertNull(serviceImpl.getActualStateAfterTransition(OpState.SAVE, OpState.DELETE)); } @Test(expected = IllegalStateException.class) public void testTransitionFromSaveToNull() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.getActualStateAfterTransition(OpState.SAVE, null); } @Test(expected = IllegalStateException.class) public void testTransitionFromNullToUpdate() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.getActualStateAfterTransition(null, OpState.UPDATE); } @Test public void testTransitionFromNullToSave() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; Assert.assertEquals(OpState.SAVE, serviceImpl.getActualStateAfterTransition(null, OpState.SAVE)); } @Test public void testTransitionFromNullToNull() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; Assert.assertNull(serviceImpl.getActualStateAfterTransition(null, null)); } @Test(expected = IllegalStateException.class) public void testTransitionFromNullToDelete() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.getActualStateAfterTransition(null, OpState.DELETE); } @Test(expected = IllegalStateException.class) public void testTransitionFromUpdateToSave() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.getActualStateAfterTransition(OpState.UPDATE, OpState.SAVE); } @Test public void testTransitionFromUpdateToUpdate() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; Assert.assertEquals(OpState.UPDATE, serviceImpl.getActualStateAfterTransition(OpState.UPDATE, OpState.UPDATE)); } @Test public void testTransitionFromUpdateToDelete() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; Assert.assertEquals(OpState.DELETE, serviceImpl.getActualStateAfterTransition(OpState.UPDATE, OpState.DELETE)); } @Test(expected = IllegalStateException.class) public void testTransitionFromUpdateToNull() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.getActualStateAfterTransition(OpState.UPDATE, null); } public void testTransitionFromDeleteToSave() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; Assert.assertEquals(OpState.SAVE, serviceImpl.getActualStateAfterTransition(OpState.DELETE, OpState.SAVE)); } @Test(expected = IllegalStateException.class) public void testTransitionFromDeleteToUpdate() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.getActualStateAfterTransition(OpState.DELETE, OpState.UPDATE); } @Test(expected = IllegalStateException.class) public void testTransitionFromDeleteToDelete() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.getActualStateAfterTransition(OpState.DELETE, OpState.DELETE); } @Test(expected = IllegalStateException.class) public void testTransitionFromDeleteToNull() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.getActualStateAfterTransition(OpState.DELETE, null); } private TransactionElement<DemoDomain> getTransactionElement(CommonReadDao<DemoDomain, String> readDao, CommonWriteDao<DemoDomain> writeDao) { TransactionElement<DemoDomain> demoElement = new TransactionElement<DemoDomain>(); DemoDomain dto = new DemoDomain(); dto.setId("1"); demoElement.setDto(dto); demoElement.setObjectType(DemoDomain.class); demoElement.setTxId("1"); demoElement.setReadDao(readDao); demoElement.setWriteDao(writeDao); return demoElement; } @Test public void testPopulateTransactionCacheWithNonExistingValueForSave() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionElement<DemoDomain> element = getTransactionElement(readDao, writeDao); mockery.checking(new Expectations() { { Sequence seq = mockery.sequence("serial"); exactly(1).of(mockFactory).createTransactionStoreKey(); TransactionStoreKey key = mockery.mock(TransactionStoreKey.class); will(returnValue(key)); inSequence(seq); exactly(1).of(key).setOpTimestamp(with(any(Long.class))); inSequence(seq); exactly(1).of(key).setTransactionId("1"); inSequence(seq); exactly(1).of(key).setObjectType(DemoDomain.class); inSequence(seq); exactly(1).of(key).setObjectId("1"); inSequence(seq); exactly(1).of(mockMemCache).getValueForIsolatedTransaction(with(same(key))); will(returnValue(null)); inSequence(seq); exactly(1).of(mockFactory).createTransactionStoreValue(); TransactionStoreValue val = mockery.mock(TransactionStoreValue.class); will(returnValue(val)); inSequence(seq); exactly(1).of(val).setCurrentState(with(same(element.getDto()))); inSequence(seq); exactly(1).of(val).setOpSequence(with(equal(0))); inSequence(seq); exactly(1).of(val).setOpState(with(equal(OpState.SAVE))); inSequence(seq); exactly(1).of(mockMemCache).storeTransactionValue(with(same(key)), with(same(val))); inSequence(seq); } }); serviceImpl.populateCache(element, OpState.SAVE); mockery.assertIsSatisfied(); } @Test public void testPopulateTransactionCacheWithNonExistingValueForNotSave() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; final CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); final CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionElement<DemoDomain> element = getTransactionElement(readDao, writeDao); mockery.checking(new Expectations() { { Sequence seq = mockery.sequence("serial"); exactly(1).of(mockFactory).createTransactionStoreKey(); TransactionStoreKey key = mockery.mock(TransactionStoreKey.class); will(returnValue(key)); inSequence(seq); exactly(1).of(key).setOpTimestamp(with(any(Long.class))); inSequence(seq); exactly(1).of(key).setTransactionId("1"); inSequence(seq); exactly(1).of(key).setObjectType(DemoDomain.class); inSequence(seq); exactly(1).of(key).setObjectId("1"); inSequence(seq); exactly(1).of(mockMemCache).getValueForIsolatedTransaction(with(same(key))); will(returnValue(null)); inSequence(seq); exactly(1).of(mockFactory).createTransactionStoreValue(); TransactionStoreValue val = mockery.mock(TransactionStoreValue.class); will(returnValue(val)); inSequence(seq); exactly(1).of(val).setCurrentState(with(same(element.getDto()))); inSequence(seq); exactly(1).of(val).setOpSequence(with(equal(0))); inSequence(seq); exactly(1).of(val).setOpState(with(equal(OpState.UPDATE))); inSequence(seq); exactly(1).of(key).getObjectId(); will(returnValue("1")); DemoDomain orgDemo = new DemoDomain(); exactly(1).of(readDao).getById("1"); will(returnValue(orgDemo)); inSequence(seq); exactly(1).of(val).setOriginalState(with(same(orgDemo))); inSequence(seq); exactly(1).of(mockMemCache).storeTransactionValue(with(same(key)), with(same(val))); inSequence(seq); } }); serviceImpl.populateCache(element, OpState.UPDATE); mockery.assertIsSatisfied(); } @Test public void testPopulateTransactionCacheWithExistingValue() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionElement<DemoDomain> element = getTransactionElement(readDao, writeDao); mockery.checking(new Expectations() { { Sequence seq = mockery.sequence("serial"); exactly(1).of(mockFactory).createTransactionStoreKey(); TransactionStoreKey key = mockery.mock(TransactionStoreKey.class); will(returnValue(key)); inSequence(seq); exactly(1).of(key).setOpTimestamp(with(any(Long.class))); inSequence(seq); exactly(1).of(key).setTransactionId("1"); inSequence(seq); exactly(1).of(key).setObjectType(DemoDomain.class); inSequence(seq); exactly(1).of(key).setObjectId("1"); inSequence(seq); TransactionStoreValue val = mockery.mock(TransactionStoreValue.class); Pair<TransactionStoreKey, TransactionStoreValue> pair = new Pair<TransactionStoreKey, TransactionStoreValue>( key, val); exactly(1).of(mockMemCache).getValueForIsolatedTransaction(with(same(key))); will(returnValue(pair)); inSequence(seq); exactly(1).of(val).setCurrentState(with(same(element.getDto()))); inSequence(seq); exactly(1).of(val).getOpState(); will(returnValue(OpState.SAVE)); inSequence(seq); exactly(1).of(val).setOpState(with(equal(OpState.SAVE))); inSequence(seq); } }); serviceImpl.populateCache(element, OpState.UPDATE); mockery.assertIsSatisfied(); } @Test public void testUpdate() { final TransactionService service = injector.getInstance(TransactionService.class); final CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); final CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionElement<DemoDomain> element = getTransactionElement(readDao, writeDao); mockery.checking(new Expectations() { { exactly(1).of(mockFactory).createTransactionStoreKey(); TransactionStoreKey key = mockery.mock(TransactionStoreKey.class); will(returnValue(key)); exactly(1).of(key).setOpTimestamp(with(any(Long.class))); exactly(1).of(key).setTransactionId("1"); exactly(1).of(key).setObjectType(DemoDomain.class); exactly(1).of(key).setObjectId("1"); TransactionStoreValue val = mockery.mock(TransactionStoreValue.class); Pair<TransactionStoreKey, TransactionStoreValue> pair = new Pair<TransactionStoreKey, TransactionStoreValue>( key, val); exactly(1).of(mockMemCache).getValueForIsolatedTransaction(with(same(key))); will(returnValue(pair)); exactly(1).of(val).setCurrentState(with(same(element.getDto()))); exactly(1).of(val).getOpState(); will(returnValue(OpState.SAVE)); exactly(1).of(val).setOpState(with(equal(OpState.SAVE))); } }); service.update(element); mockery.assertIsSatisfied(); } @Test public void testDelete() { final TransactionService service = injector.getInstance(TransactionService.class); final CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); final CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionElement<DemoDomain> element = getTransactionElement(readDao, writeDao); mockery.checking(new Expectations() { { exactly(1).of(mockFactory).createTransactionStoreKey(); TransactionStoreKey key = mockery.mock(TransactionStoreKey.class); will(returnValue(key)); exactly(1).of(key).setOpTimestamp(with(any(Long.class))); exactly(1).of(key).setTransactionId("1"); exactly(1).of(key).setObjectType(DemoDomain.class); exactly(1).of(key).setObjectId("1"); TransactionStoreValue val = mockery.mock(TransactionStoreValue.class); Pair<TransactionStoreKey, TransactionStoreValue> pair = new Pair<TransactionStoreKey, TransactionStoreValue>( key, val); exactly(1).of(mockMemCache).getValueForIsolatedTransaction(with(same(key))); will(returnValue(pair)); exactly(1).of(val).setCurrentState(with(same(element.getDto()))); exactly(1).of(val).getOpState(); will(returnValue(OpState.UPDATE)); exactly(1).of(val).setOpState(with(equal(OpState.DELETE))); } }); service.delete(element); mockery.assertIsSatisfied(); } @Test public void testSaveWithId() { final TransactionService service = injector.getInstance(TransactionService.class); final CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); final CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionElement<DemoDomain> element = getTransactionElement(readDao, writeDao); mockery.checking(new Expectations() { { exactly(1).of(mockFactory).createTransactionStoreKey(); TransactionStoreKey key = mockery.mock(TransactionStoreKey.class); will(returnValue(key)); exactly(1).of(key).setOpTimestamp(with(any(Long.class))); exactly(1).of(key).setTransactionId("1"); exactly(1).of(key).setObjectType(DemoDomain.class); exactly(1).of(key).setObjectId("1"); TransactionStoreValue val = mockery.mock(TransactionStoreValue.class); Pair<TransactionStoreKey, TransactionStoreValue> pair = new Pair<TransactionStoreKey, TransactionStoreValue>( key, val); exactly(1).of(mockMemCache).getValueForIsolatedTransaction(with(same(key))); will(returnValue(pair)); exactly(1).of(val).setCurrentState(with(same(element.getDto()))); exactly(1).of(val).getOpState(); will(returnValue(null)); exactly(1).of(val).setOpState(with(equal(OpState.SAVE))); } }); service.save(element); mockery.assertIsSatisfied(); } @Test public void testSaveWithoutId() { final TransactionService service = injector.getInstance(TransactionService.class); final CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); final CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionElement<DemoDomain> element = getTransactionElement(readDao, writeDao); element.getDto().setId(null); mockery.checking(new Expectations() { { exactly(1).of(mockFactory).createTransactionStoreKey(); TransactionStoreKey key = mockery.mock(TransactionStoreKey.class); will(returnValue(key)); exactly(1).of(key).setOpTimestamp(with(any(Long.class))); exactly(1).of(key).setTransactionId("1"); exactly(1).of(key).setObjectType(DemoDomain.class); exactly(1).of(key).setObjectId(with(aNonNull(String.class))); TransactionStoreValue val = mockery.mock(TransactionStoreValue.class); Pair<TransactionStoreKey, TransactionStoreValue> pair = new Pair<TransactionStoreKey, TransactionStoreValue>( key, val); exactly(1).of(mockMemCache).getValueForIsolatedTransaction(with(same(key))); will(returnValue(pair)); exactly(1).of(val).setCurrentState(with(same(element.getDto()))); exactly(1).of(val).getOpState(); will(returnValue(null)); exactly(1).of(val).setOpState(with(equal(OpState.SAVE))); } }); service.save(element); mockery.assertIsSatisfied(); } @Test public void testHardRollbackWithEmptyDeque() { final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; serviceImpl.rollback(new LinkedList<Pair<TransactionStoreKey, TransactionStoreValue>>()); serviceImpl.rollback((Deque<Pair<TransactionStoreKey, TransactionStoreValue>>) null); } @Test public void testHardRollback() { final CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); final CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; ConcurrentMap<String, Pair<CommonWriteDao<? extends AbstractRepositoryDomain>, CommonReadDao<? extends AbstractRepositoryDomain, String>>> daoCache; try { final Field daoCacheField = TransactionServiceImpl.class.getDeclaredField("daoCache"); daoCacheField.setAccessible(true); daoCache = (ConcurrentMap<String, Pair<CommonWriteDao<? extends AbstractRepositoryDomain>, CommonReadDao<? extends AbstractRepositoryDomain, String>>>) daoCacheField. get(serviceImpl); daoCache.put(DemoDomain.class.getName(), new Pair<CommonWriteDao<? extends AbstractRepositoryDomain>, CommonReadDao<? extends AbstractRepositoryDomain, String>>( writeDao, readDao)); } catch (Exception ex) { throw new IllegalStateException(ex); } final TransactionStoreKey k1 = mockery.mock(TransactionStoreKey.class, "k1"), k2 = mockery.mock( TransactionStoreKey.class, "k2"); final TransactionStoreValue v1 = mockery.mock(TransactionStoreValue.class, "v1"), v2 = mockery.mock( TransactionStoreValue.class, "v2"); final TransactionStoreKey k3 = mockery.mock(TransactionStoreKey.class, "k3"), k4 = mockery.mock( TransactionStoreKey.class, "k4"); final TransactionStoreValue v3 = mockery.mock(TransactionStoreValue.class, "v3"), v4 = mockery.mock( TransactionStoreValue.class, "v4"); final Deque<Pair<TransactionStoreKey, TransactionStoreValue>> linkedList = new LinkedList<Pair<TransactionStoreKey, TransactionStoreValue>>(); linkedList.push(new Pair<TransactionStoreKey, TransactionStoreValue>(k1, v1)); linkedList.push(new Pair<TransactionStoreKey, TransactionStoreValue>(k2, v2)); linkedList.push(new Pair<TransactionStoreKey, TransactionStoreValue>(k3, v3)); linkedList.push(new Pair<TransactionStoreKey, TransactionStoreValue>(k4, v4)); mockery.checking(new Expectations() { { DemoDomain d1 = new DemoDomain(); Sequence seq = mockery.sequence("hardRollback"); exactly(1).of(k4).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v4).getOpState(); will(returnValue(OpState.SAVE)); inSequence(seq); exactly(1).of(v4).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).delete(d1); inSequence(seq); exactly(1).of(k3).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v3).getOpState(); will(returnValue(OpState.UPDATE)); inSequence(seq); exactly(1).of(v3).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).update(d1); inSequence(seq); exactly(1).of(k2).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v2).getOpState(); will(returnValue(OpState.DELETE)); inSequence(seq); exactly(1).of(v2).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).save(d1); inSequence(seq); exactly(1).of(k1).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v1).getOpState(); will(returnValue(null)); inSequence(seq); } }); serviceImpl.rollback(linkedList); mockery.assertIsSatisfied(); } @Test public void testCommitWithBlankTxId() { final TransactionService service = injector.getInstance(TransactionService.class); service.commit(null); service.commit(""); service.commit(" "); } @Test public void testCommitWithNullOrEmptyTransactionOps() { final TransactionService service = injector.getInstance(TransactionService.class); mockery.checking(new Expectations() { { exactly(1).of(mockMemCache).getTransactionParticipants("1"); will(returnValue(null)); exactly(1).of(mockMemCache).getTransactionParticipants("1"); will(returnValue(new ArrayList<Pair<TransactionStoreKey, TransactionStoreValue>>())); } }); service.commit("1"); service.commit("1"); mockery.assertIsSatisfied(); } @Test public void testCommit() { final CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); final CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; ConcurrentMap<String, Pair<CommonWriteDao<? extends AbstractRepositoryDomain>, CommonReadDao<? extends AbstractRepositoryDomain, String>>> daoCache; try { final Field daoCacheField = TransactionServiceImpl.class.getDeclaredField("daoCache"); daoCacheField.setAccessible(true); daoCache = (ConcurrentMap<String, Pair<CommonWriteDao<? extends AbstractRepositoryDomain>, CommonReadDao<? extends AbstractRepositoryDomain, String>>>) daoCacheField. get(serviceImpl); daoCache.put(DemoDomain.class.getName(), new Pair<CommonWriteDao<? extends AbstractRepositoryDomain>, CommonReadDao<? extends AbstractRepositoryDomain, String>>( writeDao, readDao)); } catch (Exception ex) { throw new IllegalStateException(ex); } final TransactionStoreKey k1 = mockery.mock(TransactionStoreKey.class, "k1"), k2 = mockery.mock( TransactionStoreKey.class, "k2"); final TransactionStoreValue v1 = mockery.mock(TransactionStoreValue.class, "v1"), v2 = mockery.mock( TransactionStoreValue.class, "v2"); final TransactionStoreKey k3 = mockery.mock(TransactionStoreKey.class, "k3"), k4 = mockery.mock( TransactionStoreKey.class, "k4"); final TransactionStoreValue v3 = mockery.mock(TransactionStoreValue.class, "v3"), v4 = mockery.mock( TransactionStoreValue.class, "v4"); final List<Pair<TransactionStoreKey, TransactionStoreValue>> opsList = new ArrayList<Pair<TransactionStoreKey, TransactionStoreValue>>(); opsList.add(new Pair<TransactionStoreKey, TransactionStoreValue>(k1, v1)); opsList.add(new Pair<TransactionStoreKey, TransactionStoreValue>(k2, v2)); opsList.add(new Pair<TransactionStoreKey, TransactionStoreValue>(k3, v3)); opsList.add(new Pair<TransactionStoreKey, TransactionStoreValue>(k4, v4)); mockery.checking(new Expectations() { { DemoDomain d1 = new DemoDomain(); Sequence seq = mockery.sequence("commit"); exactly(1).of(mockMemCache).getTransactionParticipants("1"); will(returnValue(opsList)); inSequence(seq); atLeast(1).of(v1).getOpSequence(); will(returnValue(3)); atLeast(1).of(v2).getOpSequence(); will(returnValue(2)); atLeast(1).of(v3).getOpSequence(); will(returnValue(1)); atLeast(1).of(v4).getOpSequence(); will(returnValue(0)); exactly(1).of(k4).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v4).getOpState(); will(returnValue(OpState.SAVE)); inSequence(seq); exactly(1).of(v4).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).save(d1); inSequence(seq); exactly(1).of(k3).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v3).getOpState(); will(returnValue(OpState.UPDATE)); inSequence(seq); exactly(1).of(v3).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).update(d1); inSequence(seq); exactly(1).of(k2).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v2).getOpState(); will(returnValue(OpState.DELETE)); inSequence(seq); exactly(1).of(v2).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).delete(d1); inSequence(seq); exactly(1).of(k1).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v1).getOpState(); will(returnValue(null)); inSequence(seq); } }); serviceImpl.commit("1"); mockery.assertIsSatisfied(); } @Test(expected = TransactionException.class) public void testCommitWithHardRollback() { final CommonReadDao<DemoDomain, String> readDao = mockery.mock(CommonReadDao.class); final CommonWriteDao<DemoDomain> writeDao = mockery.mock(CommonWriteDao.class); final TransactionService service = injector.getInstance(TransactionService.class); final TransactionServiceImpl serviceImpl = (TransactionServiceImpl) service; ConcurrentMap<String, Pair<CommonWriteDao<? extends AbstractRepositoryDomain>, CommonReadDao<? extends AbstractRepositoryDomain, String>>> daoCache; try { final Field daoCacheField = TransactionServiceImpl.class.getDeclaredField("daoCache"); daoCacheField.setAccessible(true); daoCache = (ConcurrentMap<String, Pair<CommonWriteDao<? extends AbstractRepositoryDomain>, CommonReadDao<? extends AbstractRepositoryDomain, String>>>) daoCacheField. get(serviceImpl); daoCache.put(DemoDomain.class.getName(), new Pair<CommonWriteDao<? extends AbstractRepositoryDomain>, CommonReadDao<? extends AbstractRepositoryDomain, String>>( writeDao, readDao)); } catch (Exception ex) { throw new IllegalStateException(ex); } final TransactionStoreKey k1 = mockery.mock(TransactionStoreKey.class, "k1"), k2 = mockery.mock( TransactionStoreKey.class, "k2"); final TransactionStoreValue v1 = mockery.mock(TransactionStoreValue.class, "v1"), v2 = mockery.mock( TransactionStoreValue.class, "v2"); final TransactionStoreKey k3 = mockery.mock(TransactionStoreKey.class, "k3"), k4 = mockery.mock( TransactionStoreKey.class, "k4"); final TransactionStoreValue v3 = mockery.mock(TransactionStoreValue.class, "v3"), v4 = mockery.mock( TransactionStoreValue.class, "v4"); final List<Pair<TransactionStoreKey, TransactionStoreValue>> opsList = new ArrayList<Pair<TransactionStoreKey, TransactionStoreValue>>(); opsList.add(new Pair<TransactionStoreKey, TransactionStoreValue>(k1, v1)); opsList.add(new Pair<TransactionStoreKey, TransactionStoreValue>(k2, v2)); opsList.add(new Pair<TransactionStoreKey, TransactionStoreValue>(k3, v3)); opsList.add(new Pair<TransactionStoreKey, TransactionStoreValue>(k4, v4)); mockery.checking(new Expectations() { { DemoDomain d1 = new DemoDomain(); Sequence seq = mockery.sequence("commitWithHardRollback"); exactly(1).of(mockMemCache).getTransactionParticipants("1"); will(returnValue(opsList)); inSequence(seq); atLeast(1).of(v1).getOpSequence(); will(returnValue(2)); atLeast(1).of(v2).getOpSequence(); will(returnValue(3)); atLeast(1).of(v3).getOpSequence(); will(returnValue(1)); atLeast(1).of(v4).getOpSequence(); will(returnValue(0)); exactly(1).of(k4).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v4).getOpState(); will(returnValue(OpState.SAVE)); inSequence(seq); exactly(1).of(v4).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).save(d1); inSequence(seq); exactly(1).of(k3).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v3).getOpState(); will(returnValue(OpState.UPDATE)); inSequence(seq); exactly(1).of(v3).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).update(d1); inSequence(seq); exactly(1).of(k1).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v1).getOpState(); will(returnValue(null)); inSequence(seq); exactly(1).of(k2).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v2).getOpState(); will(returnValue(OpState.DELETE)); inSequence(seq); exactly(1).of(v2).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).delete(d1); will(throwException(new NullPointerException())); inSequence(seq); exactly(1).of(k1).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v1).getOpState(); will(returnValue(null)); inSequence(seq); exactly(1).of(k3).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v3).getOpState(); will(returnValue(OpState.UPDATE)); inSequence(seq); exactly(1).of(v3).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).update(d1); inSequence(seq); exactly(1).of(k4).getObjectType(); will(returnValue(DemoDomain.class)); inSequence(seq); exactly(1).of(v4).getOpState(); will(returnValue(OpState.SAVE)); inSequence(seq); exactly(1).of(v4).getCurrentState(); will(returnValue(d1)); inSequence(seq); exactly(1).of(writeDao).delete(d1); inSequence(seq); } }); serviceImpl.commit("1"); mockery.assertIsSatisfied(); } }