package org.multiverse.stms.gamma.transactionalobjects.txnlong;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.multiverse.SomeUncheckedException;
import org.multiverse.TestThread;
import org.multiverse.api.Txn;
import org.multiverse.api.callables.TxnVoidCallable;
import org.multiverse.api.exceptions.DeadTxnException;
import org.multiverse.api.exceptions.PreparedTxnException;
import org.multiverse.api.exceptions.RetryError;
import org.multiverse.api.predicates.LongPredicate;
import org.multiverse.api.references.TxnLong;
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.predicates.LongPredicate.newEqualsPredicate;
import static org.multiverse.api.predicates.LongPredicate.newLargerThanOrEqualsPredicate;
import static org.multiverse.stms.gamma.GammaTestUtils.assertVersionAndValue;
public class GammaTxnLong_await2WithPredicateTest {
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();
try {
ref.await(tx, newEqualsPredicate(initialValue + 1));
fail();
} catch (RetryError expected) {
}
assertIsAborted(tx);
assertVersionAndValue(ref, initialVersion, initialValue);
}
@Test
public void whenPredicateReturnsTrue() {
long initialValue = 10;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
long initialVersion = ref.getVersion();
GammaTxn tx = stm.newDefaultTxn();
ref.await(tx, newEqualsPredicate(initialValue));
assertIsActive(tx);
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();
try {
ref.await(tx, predicate);
fail();
} catch (SomeUncheckedException expected) {
}
assertIsAborted(tx);
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();
try {
ref.await(tx, null);
fail();
} catch (NullPointerException expected) {
}
assertIsAborted(tx);
assertVersionAndValue(ref, initialVersion, initialValue);
}
@Test
public void whenNullTransaction_thenNullPointerException() {
long initialValue = 10;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
long initialVersion = ref.getVersion();
LongPredicate predicate = mock(LongPredicate.class);
try {
ref.await(null, predicate);
fail();
} catch (NullPointerException expected) {
}
verifyZeroInteractions(predicate);
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();
tx.prepare();
LongPredicate predicate = mock(LongPredicate.class);
try {
ref.await(tx, predicate);
fail();
} catch (PreparedTxnException expected) {
}
assertIsAborted(tx);
verifyZeroInteractions(predicate);
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();
tx.abort();
LongPredicate predicate = mock(LongPredicate.class);
try {
ref.await(tx, predicate);
fail();
} catch (DeadTxnException expected) {
}
assertIsAborted(tx);
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();
tx.commit();
LongPredicate predicate = mock(LongPredicate.class);
try {
ref.await(tx, predicate);
fail();
} catch (DeadTxnException expected) {
}
assertIsCommitted(tx);
verifyZeroInteractions(predicate);
assertVersionAndValue(ref, initialVersion, initialValue);
}
@Test
@Ignore
public void whenSomeWaitingNeeded() {
int initialValue = 0;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
long initialVersion = ref.getVersion();
AwaitThread thread1 = new AwaitThread(0, 10, ref);
AwaitThread thread2 = new AwaitThread(1, 20, ref);
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);
assertVersionAndValue(ref, initialVersion + 2, 20);
}
public class AwaitThread extends TestThread {
private long minimumValue;
private TxnLong ref;
public AwaitThread(int id, long minimumValue, TxnLong ref) {
super("AwaitThread-" + id);
this.minimumValue = minimumValue;
this.ref = ref;
}
@Override
public void doRun() throws Exception {
ref.getStm().getDefaultTxnExecutor().execute(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.await(tx, newLargerThanOrEqualsPredicate(minimumValue));
}
});
}
}
}