package org.multiverse.commitbarriers; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnFactory; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.exceptions.DeadTxnException; import org.multiverse.api.exceptions.TooManyRetriesException; import org.multiverse.stms.gamma.GammaStm; import org.multiverse.stms.gamma.transactionalobjects.GammaTxnInteger; import static org.junit.Assert.*; import static org.multiverse.TestUtils.*; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; public class VetoCommitBarrier_joinCommitTest { private GammaStm stm; private TxnFactory txFactory; @Before public void setUp() { stm = new GammaStm(); txFactory = stm.newTxnFactoryBuilder() .setSpeculative(false) .newTransactionFactory(); clearThreadLocalTxn(); clearCurrentThreadInterruptedStatus(); } @After public void tearDown() { clearCurrentThreadInterruptedStatus(); } @Test public void whenTransactionNull_thenNullPointerException() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); try { barrier.joinCommit(null); fail(); } catch (NullPointerException expected) { } assertTrue(barrier.isClosed()); assertEquals(0, barrier.getNumberWaiting()); } @Test @Ignore public void whenTransactionPreparable_thenAdded() { VetoCommitBarrier barrier = new VetoCommitBarrier(); GammaTxnInteger ref = new GammaTxnInteger(stm); IncThread thread = new IncThread(ref, barrier); thread.start(); sleepMs(1000); assertAlive(thread); assertTrue(barrier.isClosed()); assertEquals(1, barrier.getNumberWaiting()); } @Test @Ignore public void whenTransactionPrepared_thenAdded() { VetoCommitBarrier barrier = new VetoCommitBarrier(); GammaTxnInteger ref = new GammaTxnInteger(stm); IncThread thread = new IncThread(ref, barrier, true); thread.start(); sleepMs(1000); assertAlive(thread); assertTrue(barrier.isClosed()); assertEquals(1, barrier.getNumberWaiting()); } @Test @Ignore public void whenPrepareFails() throws InterruptedException { final VetoCommitBarrier group = new VetoCommitBarrier(); final GammaTxnInteger ref = new GammaTxnInteger(stm); FailToPrepareThread thread = new FailToPrepareThread(group, ref); thread.start(); sleepMs(1000); stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(tx, 1); } }); thread.join(); thread.assertFailedWithException(TooManyRetriesException.class); assertEquals(0, group.getNumberWaiting()); } class FailToPrepareThread extends TestThread { final VetoCommitBarrier group; final GammaTxnInteger ref; FailToPrepareThread(VetoCommitBarrier group, GammaTxnInteger ref) { super("FailedToPrepareThread"); this.group = group; this.ref = ref; setPrintStackTrace(false); } @Override public void doRun() throws Exception { stm.newTxnFactoryBuilder() .setSpeculative(false) .setMaxRetries(0) .newTxnExecutor() .execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { //we need to load it to cause a conflict ref.get(tx); sleepMs(2000); ref.incrementAndGet(tx, 1); group.joinCommit(tx); } }); } } @Test public void whenTransactionAborted_thenDeadTxnException() throws InterruptedException { Txn tx = txFactory.newTxn(); tx.abort(); VetoCommitBarrier group = new VetoCommitBarrier(); try { group.joinCommit(tx); fail(); } catch (DeadTxnException expected) { } assertTrue(group.isClosed()); assertIsAborted(tx); assertEquals(0, group.getNumberWaiting()); } @Test public void whenTransactionCommitted_thenDeadTxnException() throws InterruptedException { Txn tx = txFactory.newTxn(); tx.commit(); VetoCommitBarrier group = new VetoCommitBarrier(); try { group.joinCommit(tx); fail(); } catch (DeadTxnException expected) { } assertTrue(group.isClosed()); assertIsCommitted(tx); assertEquals(0, group.getNumberWaiting()); } @Test public void whenBarrierAborted_thenCommitBarrierOpenException() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.abort(); Txn tx = txFactory.newTxn(); try { barrier.joinCommit(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertIsActive(tx); assertTrue(barrier.isAborted()); assertEquals(0, barrier.getNumberWaiting()); } @Test public void whenCommitted_thenCommitBarrierOpenException() throws InterruptedException { VetoCommitBarrier barrier = new VetoCommitBarrier(); barrier.atomicVetoCommit(); System.out.println("barrier.state: " + barrier); Txn tx = txFactory.newTxn(); try { barrier.joinCommit(tx); fail(); } catch (CommitBarrierOpenException expected) { } assertIsActive(tx); assertTrue(barrier.isCommitted()); assertEquals(0, barrier.getNumberWaiting()); } public class IncThread extends TestThread { private final GammaTxnInteger ref; private final VetoCommitBarrier barrier; private boolean prepare; public IncThread(GammaTxnInteger ref, VetoCommitBarrier barrier) { this(ref, barrier, false); } public IncThread(GammaTxnInteger ref, VetoCommitBarrier barrier, boolean prepare) { super("IncThread"); this.barrier = barrier; this.ref = ref; this.prepare = prepare; } @Override public void doRun() throws Exception { stm.getDefaultTxnExecutor().execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { ref.incrementAndGet(tx, 1); if (prepare) { tx.prepare(); } barrier.joinCommit(tx); } }); } } }