package org.multiverse.stms.gamma;
import org.junit.Before;
import org.junit.Test;
import org.multiverse.api.Txn;
import org.multiverse.api.TxnExecutor;
import org.multiverse.api.PropagationLevel;
import org.multiverse.api.callables.TxnIntCallable;
import org.multiverse.api.callables.TxnVoidCallable;
import org.multiverse.api.exceptions.TxnMandatoryException;
import org.multiverse.api.exceptions.TxnNotAllowedException;
import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong;
import org.multiverse.stms.gamma.transactions.GammaTxn;
import org.multiverse.stms.gamma.transactions.GammaTxnFactory;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.multiverse.TestUtils.assertIsActive;
import static org.multiverse.api.TxnThreadLocal.*;
public class FatGammaTxnExecutor_propagationLevelTest implements GammaConstants {
private GammaStm stm;
@Before
public void setUp() {
stm = new GammaStm();
clearThreadLocalTxn();
}
@Test
public void whenNeverAndTransactionAvailable_thenNoTransactionAllowedException() {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.Never)
.newTxnExecutor();
GammaTxn otherTx = stm.newDefaultTxn();
setThreadLocalTxn(otherTx);
TxnVoidCallable callable = mock(TxnVoidCallable.class);
try {
executor.execute(callable);
fail();
} catch (TxnNotAllowedException expected) {
}
verifyZeroInteractions(callable);
assertIsActive(otherTx);
assertSame(otherTx, getThreadLocalTxn());
}
@Test
public void whenNeverAndNoTransactionAvailable() {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.Never)
.newTxnExecutor();
TxnIntCallable callable = new TxnIntCallable() {
@Override
public int call(Txn tx) throws Exception {
assertNull(tx);
return 10;
}
};
int result = executor.execute(callable);
assertEquals(10, result);
assertNull(getThreadLocalTxn());
}
@Test
public void whenMandatoryAndNoTransactionAvailable_thenNoTransactionFoundException() {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.Mandatory)
.newTxnExecutor();
TxnVoidCallable callable = mock(TxnVoidCallable.class);
try {
executor.execute(callable);
fail();
} catch (TxnMandatoryException expected) {
}
verifyZeroInteractions(callable);
assertNull(getThreadLocalTxn());
}
@Test
public void whenMandatoryAndTransactionAvailable_thenExistingTransactionUsed() {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.Mandatory)
.newTxnExecutor();
final GammaTxn otherTx = stm.newDefaultTxn();
setThreadLocalTxn(otherTx);
TxnIntCallable callable = new TxnIntCallable() {
@Override
public int call(Txn tx) throws Exception {
assertSame(otherTx, tx);
return 10;
}
};
int result = executor.execute(callable);
assertEquals(10, result);
assertIsActive(otherTx);
assertSame(otherTx, getThreadLocalTxn());
}
@Test
public void whenRequiresAndNoTransactionAvailable_thenNewTransactionUsed() {
GammaTxnFactory txFactory = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.Requires)
.newTransactionFactory();
final GammaTxnLong ref = new GammaTxnLong(stm);
TxnIntCallable callable = new TxnIntCallable() {
@Override
public int call(Txn tx) throws Exception {
assertNotNull(tx);
GammaTxn btx = (GammaTxn) tx;
ref.incrementAndGet(1);
return 10;
}
};
int result = new FatGammaTxnExecutor(txFactory).execute(callable);
assertEquals(10, result);
assertNull(getThreadLocalTxn());
assertEquals(1, ref.atomicGet());
}
@Test
public void whenRequiresAndTransactionAvailable_thenExistingTransactionUsed() {
GammaTxnFactory txFactory = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.Requires)
.newTransactionFactory();
final GammaTxn existingTx = stm.newDefaultTxn();
setThreadLocalTxn(existingTx);
final GammaTxnLong ref = new GammaTxnLong(stm);
TxnIntCallable callable = new TxnIntCallable() {
@Override
public int call(Txn tx) throws Exception {
assertSame(existingTx, tx);
GammaTxn btx = (GammaTxn) tx;
ref.incrementAndGet(btx, 1);
return 10;
}
};
int result = new FatGammaTxnExecutor(txFactory).execute(callable);
assertEquals(10, result);
assertSame(existingTx, getThreadLocalTxn());
assertIsActive(existingTx);
//since the value hasn't committed yet, it still is zero (the value before the transaction began).
assertEquals(0, ref.atomicGet());
}
@Test
public void whenRequiresNewAndNoTransactionAvailable_thenNewTransactionCreated() {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.RequiresNew)
.newTxnExecutor();
final GammaTxnLong ref = new GammaTxnLong(stm, 0);
TxnIntCallable callable = new TxnIntCallable() {
@Override
public int call(Txn tx) throws Exception {
assertNotNull(tx);
GammaTxn btx = (GammaTxn) tx;
ref.incrementAndGet(btx, 1);
return 10;
}
};
int result = executor.execute(callable);
assertEquals(10, result);
assertEquals(1, ref.atomicGet());
assertNull(getThreadLocalTxn());
}
@Test
public void whenRequiresNewAndTransactionAvailable_thenExistingTransactionSuspended() {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.RequiresNew)
.newTxnExecutor();
final GammaTxn otherTx = stm.newDefaultTxn();
setThreadLocalTxn(otherTx);
final GammaTxnLong ref = new GammaTxnLong(stm, 10);
TxnIntCallable callable = new TxnIntCallable() {
@Override
public int call(Txn tx) throws Exception {
assertNotNull(tx);
assertNotSame(otherTx, tx);
GammaTxn btx = (GammaTxn) tx;
ref.incrementAndGet(btx, 1);
return 1;
}
};
int result = executor.execute(callable);
assertEquals(1, result);
assertEquals(11, ref.atomicGet());
assertSame(otherTx, getThreadLocalTxn());
assertIsActive(otherTx);
}
@Test
public void whenSupportsAndTransactionAvailable() {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.Supports)
.newTxnExecutor();
final GammaTxn otherTx = stm.newDefaultTxn();
setThreadLocalTxn(otherTx);
TxnIntCallable callable = new TxnIntCallable() {
@Override
public int call(Txn tx) throws Exception {
assertSame(otherTx, tx);
return 10;
}
};
int result = executor.execute(callable);
assertEquals(10, result);
assertIsActive(otherTx);
assertSame(otherTx, getThreadLocalTxn());
}
@Test
public void whenSupportsAndNoTransactionAvailable() {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setPropagationLevel(PropagationLevel.Supports)
.newTxnExecutor();
TxnIntCallable callable = new TxnIntCallable() {
@Override
public int call(Txn tx) throws Exception {
assertNull(tx);
return 10;
}
};
int result = executor.execute(callable);
assertEquals(10, result);
assertNull(getThreadLocalTxn());
}
}