package org.multiverse.stms.gamma.transactions.fat; import org.junit.Before; import org.junit.Test; import org.multiverse.api.LockMode; import org.multiverse.api.TxnStatus; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.functions.LongFunction; import org.multiverse.api.lifecycle.TxnEvent; import org.multiverse.api.lifecycle.TxnListener; import org.multiverse.stms.gamma.GammaConstants; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactionalobjects.Tranlocal; import org.multiverse.stms.gamma.transactions.GammaTxn; import org.multiverse.stms.gamma.transactions.GammaTxnConfig; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.multiverse.TestUtils.assertIsAborted; import static org.multiverse.stms.gamma.GammaTestUtils.*; public abstract class FatGammaTxn_abortTest<T extends GammaTxn> implements GammaConstants { protected GammaStm stm; @Before public void setUp() { stm = new GammaStm(); } protected abstract T newTransaction(); protected abstract T newTransaction(GammaTxnConfig config); protected abstract void assertCleaned(T tx); @Test public void listener_whenNormalListenerAvailable() { T tx = newTransaction(); TxnListener listener = mock(TxnListener.class); tx.register(listener); tx.abort(); assertIsAborted(tx); //verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PostAbort); } @Test public void listener_whenPermanentListenerAvailable() { TxnListener listener = mock(TxnListener.class); GammaTxnConfig config = new GammaTxnConfig(stm) .addPermanentListener(listener); T tx = newTransaction(config); tx.abort(); assertIsAborted(tx); //verify(listener).notify(tx, TxnEvent.PrePrepare); verify(listener).notify(tx, TxnEvent.PostAbort); } @Test public void whenUnused() { T tx = newTransaction(); tx.abort(); assertEquals(TxnStatus.Aborted, tx.getStatus()); } @Test public void locking_whenHasConstructed_thenRemainLocked() { GammaTxn tx = newTransaction(); GammaTxnLong ref = new GammaTxnLong(tx); Tranlocal write = tx.getRefTranlocal(ref); tx.abort(); assertIsAborted(tx); assertLockMode(ref, LOCKMODE_EXCLUSIVE); assertSurplus(ref, 1); assertWriteBiased(ref); assertVersionAndValue(ref, 0, 0); assertFalse(write.hasDepartObligation()); assertTrue(write.isConstructing()); } @Test public void whenContainsCommutes() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); LongFunction function = mock(LongFunction.class); ref.commute(tx, function); Tranlocal tranlocal = tx.getRefTranlocal(ref); tx.abort(); assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); assertNull(tranlocal.headCallable); } @Test public void whenHasRead() { whenHasRead(LockMode.None); whenHasRead(LockMode.Read); whenHasRead(LockMode.Write); whenHasRead(LockMode.Exclusive); } public void whenHasRead(LockMode readLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForRead(tx, readLockMode.asInt()); tx.abort(); assertIsAborted(tx); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertNull(tranlocal.owner); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.getVersion()); assertCleaned(tx); } @Test public void whenHasWrite() { whenHasWrite(LockMode.None); whenHasWrite(LockMode.Read); whenHasWrite(LockMode.Write); whenHasWrite(LockMode.Exclusive); } public void whenHasWrite(LockMode writeLockMode) { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); T tx = newTransaction(); Tranlocal tranlocal = ref.openForWrite(tx, writeLockMode.asInt()); tx.abort(); assertEquals(TxnStatus.Aborted, tx.getStatus()); assertEquals(LOCKMODE_NONE, tranlocal.lockMode); assertNull(tranlocal.owner); assertEquals(initialValue, ref.long_value); assertEquals(initialVersion, ref.getVersion()); assertCleaned(tx); } @Test public void whenAborted() { T tx = newTransaction(); tx.abort(); tx.abort(); assertEquals(TxnStatus.Aborted, tx.getStatus()); assertCleaned(tx); } @Test public void whenCommitted_thenDeadTxnException() { T tx = newTransaction(); tx.commit(); try { tx.abort(); fail(); } catch (DeadTxnException expected) { } assertEquals(TxnStatus.Committed, tx.getStatus()); assertCleaned(tx); } }