package org.multiverse.stms.gamma.integration.composability;
import org.junit.Before;
import org.junit.Test;
import org.multiverse.SomeUncheckedException;
import org.multiverse.api.StmUtils;
import org.multiverse.api.Txn;
import org.multiverse.api.callables.TxnVoidCallable;
import org.multiverse.api.references.TxnInteger;
import static org.junit.Assert.*;
import static org.multiverse.api.StmUtils.newTxnInteger;
import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn;
public class ComposabilityTest {
@Before
public void setUp() {
clearThreadLocalTxn();
}
@Test
public void whenChangeMadeInOneSibling_thenItWillBeVisibleInNextSubling() {
final int initialValue = 10;
final TxnInteger ref = newTxnInteger(initialValue);
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.increment();
}
});
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
assertEquals(initialValue + 1, ref.get());
ref.increment();
}
});
assertEquals(initialValue + 2, ref.get());
}
});
assertEquals(initialValue + 2, ref.atomicGet());
}
@Test
public void whenMultipleSiblings_thenSameTransaction() {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(final Txn outerTx) throws Exception {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn innerTx) throws Exception {
assertSame(innerTx, outerTx);
}
});
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn innerTx) throws Exception {
assertSame(innerTx, outerTx);
}
});
}
});
}
@Test
public void whenComposingTransaction_thenInnerAndOuterTransactionAreTheSame() {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(final Txn outerTx) throws Exception {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn innerTx) throws Exception {
assertSame(innerTx, outerTx);
}
});
}
});
}
@Test
public void whenSurroundingTransactionFails_thenChangesInInnerTransactionWillRollback() {
int initialValue = 10;
final TxnInteger ref = newTxnInteger(initialValue);
try {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.increment();
}
});
throw new SomeUncheckedException();
}
});
fail();
} catch (SomeUncheckedException expected) {
}
assertEquals(initialValue, ref.atomicGet());
}
@Test
public void whenInnerTransactionFails_thenOuterTransactionWillRollback() {
int initialValue = 10;
final TxnInteger ref = newTxnInteger(initialValue);
try {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.increment();
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
throw new SomeUncheckedException();
}
});
}
});
fail();
} catch (SomeUncheckedException expected) {
}
assertEquals(initialValue, ref.atomicGet());
}
@Test
public void whenSiblingFails_thenAllRollback() {
int initialValue = 10;
final TxnInteger ref = newTxnInteger(initialValue);
try {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.increment();
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.increment();
}
});
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
throw new SomeUncheckedException();
}
});
}
});
fail();
} catch (SomeUncheckedException expected) {
}
assertEquals(initialValue, ref.atomicGet());
}
@Test
public void whenOuterTransactionMakesChange_thenItWillBeVisibleInInnerTransaction() {
final int initialValue = 10;
final TxnInteger ref = newTxnInteger(initialValue);
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.increment();
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
assertEquals(initialValue + 1, ref.get());
}
});
}
});
assertEquals(initialValue + 1, ref.atomicGet());
}
@Test
public void whenInnerTransactionMakesChange_thenItWillBeVisibleInOuterTransaction() {
final int initialValue = 10;
final TxnInteger ref = newTxnInteger(initialValue);
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.increment();
}
});
assertEquals(initialValue + 1, ref.get());
}
});
assertEquals(initialValue + 1, ref.atomicGet());
}
@Test
public void whenInnerAndOuterChanges_thenWillCommitAsOne() {
final int initialValue = 10;
final TxnInteger ref = newTxnInteger(initialValue);
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.increment();
StmUtils.atomic(new TxnVoidCallable() {
@Override
public void call(Txn tx) throws Exception {
ref.increment();
}
});
ref.increment();
}
});
assertEquals(initialValue + 3, ref.atomicGet());
}
}