package org.multiverse.stms.gamma.integration.readonly;
import org.junit.Before;
import org.junit.Test;
import org.multiverse.api.Txn;
import org.multiverse.api.TxnExecutor;
import org.multiverse.api.callables.TxnCallable;
import org.multiverse.api.callables.TxnLongCallable;
import org.multiverse.api.callables.TxnVoidCallable;
import org.multiverse.api.exceptions.ReadonlyException;
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.*;
import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance;
import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn;
public class ReadonlyTest {
private GammaStm stm;
@Before
public void setUp() {
clearThreadLocalTxn();
stm = (GammaStm) getGlobalStmInstance();
}
@Test
public void whenReadonly_thenUpdateFails() {
GammaTxnLong ref = new GammaTxnLong(stm);
try {
updateInReadonlyMethod(ref, 10);
fail();
} catch (ReadonlyException expected) {
}
assertEquals(0, ref.atomicGet());
}
public void updateInReadonlyMethod(final GammaTxnLong ref, final int newValue) {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setReadonly(true)
.newTxnExecutor();
executor.execute(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
GammaTxn btx = (GammaTxn) tx;
ref.getAndSet(btx, newValue);
}
});
}
@Test
public void whenReadonly_thenCreationOfNewTxnObjectNotFails() {
try {
readonly_createNewTransactionObject(10);
fail();
} catch (ReadonlyException expected) {
}
}
public void readonly_createNewTransactionObject(final long value) {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setReadonly(true)
.newTxnExecutor();
executor.execute(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
GammaTxn btx = (GammaTxn) tx;
GammaTxnLong ref = new GammaTxnLong(btx);
ref.openForConstruction(btx).long_value = value;
}
});
}
@Test
public void whenReadonly_thenCreationOfNonTxnObjectSucceeds() {
Integer ref = readonly_createNormalObject(100);
assertNotNull(ref);
assertEquals(100, ref.intValue());
}
public Integer readonly_createNormalObject(final int value) {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setReadonly(true)
.newTxnExecutor();
return executor.execute(new TxnCallable<Integer>() {
@Override
public Integer call(Txn tx) throws Exception {
return new Integer(value);
}
});
}
@Test
public void whenReadonly_thenReadAllowed() {
GammaTxnLong ref = new GammaTxnLong(stm, 10);
long result = readInReadonlyMethod(ref);
assertEquals(10, result);
assertEquals(10, ref.atomicGet());
}
public long readInReadonlyMethod(final GammaTxnLong ref) {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setReadonly(true)
.newTxnExecutor();
return executor.execute(new TxnLongCallable() {
@Override
public long call(Txn tx) throws Exception {
GammaTxn btx = (GammaTxn) tx;
return ref.get(btx);
}
});
}
@Test
public void whenUpdate_thenCreationOfNewTxnObjectsSucceeds() {
GammaTxnLong ref = update_createNewTransactionObject(100);
assertNotNull(ref);
assertEquals(100, ref.atomicGet());
}
public GammaTxnLong update_createNewTransactionObject(final int value) {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setReadonly(false)
.newTxnExecutor();
return executor.execute(new TxnCallable<GammaTxnLong>() {
@Override
public GammaTxnLong call(Txn tx) throws Exception {
GammaTxn btx = (GammaTxn) tx;
GammaTxnLong ref = new GammaTxnLong(btx);
ref.openForConstruction(btx).long_value = value;
return ref;
}
});
}
@Test
public void whenUpdate_thenCreationOfNonTxnObjectSucceeds() {
Integer ref = update_createNormalObject(100);
assertNotNull(ref);
assertEquals(100, ref.intValue());
}
public Integer update_createNormalObject(final int value) {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setReadonly(false)
.newTxnExecutor();
return executor.execute(new TxnCallable<Integer>() {
@Override
public Integer call(Txn tx) throws Exception {
return new Integer(value);
}
});
}
@Test
public void whenUpdate_thenReadSucceeds() {
GammaTxnLong ref = new GammaTxnLong(stm, 10);
long result = readInUpdateMethod(ref);
assertEquals(10, result);
assertEquals(10, ref.atomicGet());
}
public long readInUpdateMethod(final GammaTxnLong ref) {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setReadonly(false)
.newTxnExecutor();
return executor.execute(new TxnLongCallable() {
@Override
public long call(Txn tx) throws Exception {
GammaTxn btx = (GammaTxn) tx;
return ref.get(btx);
}
});
}
@Test
public void whenUpdate_thenUpdateSucceeds() {
GammaTxnLong ref = new GammaTxnLong(stm);
updateInUpdateMethod(ref, 10);
assertEquals(10, ref.atomicGet());
}
public void updateInUpdateMethod(final GammaTxnLong ref, final int newValue) {
TxnExecutor executor = stm.newTxnFactoryBuilder()
.setReadonly(false)
.newTxnExecutor();
executor.execute(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
assertFalse(tx.getConfig().isReadonly());
GammaTxn btx = (GammaTxn) tx;
ref.getAndSet(btx, newValue);
}
});
}
@Test
public void whenDefault_thenUpdateSuccess() {
GammaTxnLong ref = new GammaTxnLong(stm);
defaultTransactionalMethod(ref);
assertEquals(1, ref.atomicGet());
}
public void defaultTransactionalMethod(final GammaTxnLong ref) {
stm.newTxnFactoryBuilder().newTxnExecutor().execute(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
assertFalse(tx.getConfig().isReadonly());
GammaTxn btx = (GammaTxn) tx;
ref.getAndSet(btx, ref.get(btx) + 1);
}
});
}
}