package org.multiverse.stms.gamma.transactionalobjects.txnlong; import org.junit.Before; import org.junit.Test; import org.multiverse.SomeUncheckedException; import org.multiverse.api.exceptions.*; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.PreparedTxnException; import org.multiverse.api.predicates.LongPredicate; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong; import org.multiverse.stms.gamma.transactions.GammaTxn; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; import static org.multiverse.api.TxnThreadLocal.setThreadLocalTxn; import static org.multiverse.api.predicates.LongPredicate.newEqualsPredicate; import static org.multiverse.stms.gamma.GammaTestUtils.assertRefHasNoLocks; import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue; public class GammaTxnLong_await1WithPredicateTest { private GammaStm stm; @Before public void setUp() { stm = new GammaStm(); clearThreadLocalTxn(); } @Test public void whenPredicateEvaluatesToFalse() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setFat() .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); try { ref.await(newEqualsPredicate(initialValue + 1)); fail(); } catch (RetryError expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPredicateReturnsTrue() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newTxnFactoryBuilder() .setFat() .newTransactionFactory() .newTxn(); setThreadLocalTxn(tx); ref.await(newEqualsPredicate(initialValue)); assertIsActive(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenPredicateThrowsException_thenTransactionAborted() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongPredicate predicate = mock(LongPredicate.class); when(predicate.evaluate(initialValue)).thenThrow(new SomeUncheckedException()); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.await(predicate); fail(); } catch (SomeUncheckedException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNullPredicate_thenTransactionAbortedAndNullPointerException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); try { ref.await(null); fail(); } catch (NullPointerException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenNoTransaction_thenTxnMandatoryException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(predicate); fail(); } catch (TxnMandatoryException expected) { } verifyZeroInteractions(predicate); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionPrepared_thenPreparedTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.prepare(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(predicate); fail(); } catch (PreparedTxnException expected) { } assertIsAborted(tx); verifyZeroInteractions(predicate); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionAborted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.abort(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(predicate); fail(); } catch (DeadTxnException expected) { } assertIsAborted(tx); assertRefHasNoLocks(ref); verifyZeroInteractions(predicate); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenTransactionCommitted_thenDeadTxnException() { long initialValue = 10; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); GammaTxn tx = stm.newDefaultTxn(); setThreadLocalTxn(tx); tx.commit(); LongPredicate predicate = mock(LongPredicate.class); try { ref.await(predicate); fail(); } catch (DeadTxnException expected) { } assertIsCommitted(tx); assertRefHasNoLocks(ref); verifyZeroInteractions(predicate); assertVersionAndValue(ref, initialVersion, initialValue); } @Test public void whenSomeWaitingNeeded() { int initialValue = 0; GammaTxnLong ref = new GammaTxnLong(stm, initialValue); long initialVersion = ref.getVersion(); TxnLongAwaitThread thread1 = new TxnLongAwaitThread(ref, 10); TxnLongAwaitThread thread2 = new TxnLongAwaitThread(ref, 20); thread1.start(); thread2.start(); sleepMs(1000); assertAlive(thread1, thread2); ref.atomicSet(10); assertEventuallyNotAlive(thread1); assertNothingThrown(thread1); assertAlive(thread2); ref.atomicSet(20); assertEventuallyNotAlive(thread2); assertNothingThrown(thread2); assertRefHasNoLocks(ref); assertVersionAndValue(ref, initialVersion + 2, 20); } }