package org.multiverse.stms.gamma.transactions.fat;
import org.junit.Before;
import org.junit.Test;
import org.multiverse.api.LockMode;
import org.multiverse.api.TxnStatus;
import org.multiverse.api.exceptions.DeadTxnException;
import org.multiverse.api.functions.LongFunction;
import org.multiverse.api.lifecycle.TxnEvent;
import org.multiverse.api.lifecycle.TxnListener;
import org.multiverse.stms.gamma.GammaConstants;
import org.multiverse.stms.gamma.GammaStm;
import org.multiverse.stms.gamma.transactionalobjects.GammaTxnLong;
import org.multiverse.stms.gamma.transactionalobjects.Tranlocal;
import org.multiverse.stms.gamma.transactions.GammaTxn;
import org.multiverse.stms.gamma.transactions.GammaTxnConfig;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.multiverse.TestUtils.assertIsAborted;
import static org.multiverse.stms.gamma.GammaTestUtils.*;
public abstract class FatGammaTxn_abortTest<T extends GammaTxn> implements GammaConstants {
protected GammaStm stm;
@Before
public void setUp() {
stm = new GammaStm();
}
protected abstract T newTransaction();
protected abstract T newTransaction(GammaTxnConfig config);
protected abstract void assertCleaned(T tx);
@Test
public void listener_whenNormalListenerAvailable() {
T tx = newTransaction();
TxnListener listener = mock(TxnListener.class);
tx.register(listener);
tx.abort();
assertIsAborted(tx);
//verify(listener).notify(tx, TxnEvent.PrePrepare);
verify(listener).notify(tx, TxnEvent.PostAbort);
}
@Test
public void listener_whenPermanentListenerAvailable() {
TxnListener listener = mock(TxnListener.class);
GammaTxnConfig config = new GammaTxnConfig(stm)
.addPermanentListener(listener);
T tx = newTransaction(config);
tx.abort();
assertIsAborted(tx);
//verify(listener).notify(tx, TxnEvent.PrePrepare);
verify(listener).notify(tx, TxnEvent.PostAbort);
}
@Test
public void whenUnused() {
T tx = newTransaction();
tx.abort();
assertEquals(TxnStatus.Aborted, tx.getStatus());
}
@Test
public void locking_whenHasConstructed_thenRemainLocked() {
GammaTxn tx = newTransaction();
GammaTxnLong ref = new GammaTxnLong(tx);
Tranlocal write = tx.getRefTranlocal(ref);
tx.abort();
assertIsAborted(tx);
assertLockMode(ref, LOCKMODE_EXCLUSIVE);
assertSurplus(ref, 1);
assertWriteBiased(ref);
assertVersionAndValue(ref, 0, 0);
assertFalse(write.hasDepartObligation());
assertTrue(write.isConstructing());
}
@Test
public void whenContainsCommutes() {
long initialValue = 10;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
long initialVersion = ref.getVersion();
T tx = newTransaction();
LongFunction function = mock(LongFunction.class);
ref.commute(tx, function);
Tranlocal tranlocal = tx.getRefTranlocal(ref);
tx.abort();
assertIsAborted(tx);
assertRefHasNoLocks(ref);
assertVersionAndValue(ref, initialVersion, initialValue);
assertNull(tranlocal.headCallable);
}
@Test
public void whenHasRead() {
whenHasRead(LockMode.None);
whenHasRead(LockMode.Read);
whenHasRead(LockMode.Write);
whenHasRead(LockMode.Exclusive);
}
public void whenHasRead(LockMode readLockMode) {
long initialValue = 10;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
long initialVersion = ref.getVersion();
T tx = newTransaction();
Tranlocal tranlocal = ref.openForRead(tx, readLockMode.asInt());
tx.abort();
assertIsAborted(tx);
assertEquals(LOCKMODE_NONE, tranlocal.lockMode);
assertNull(tranlocal.owner);
assertEquals(initialValue, ref.long_value);
assertEquals(initialVersion, ref.getVersion());
assertCleaned(tx);
}
@Test
public void whenHasWrite() {
whenHasWrite(LockMode.None);
whenHasWrite(LockMode.Read);
whenHasWrite(LockMode.Write);
whenHasWrite(LockMode.Exclusive);
}
public void whenHasWrite(LockMode writeLockMode) {
long initialValue = 10;
GammaTxnLong ref = new GammaTxnLong(stm, initialValue);
long initialVersion = ref.getVersion();
T tx = newTransaction();
Tranlocal tranlocal = ref.openForWrite(tx, writeLockMode.asInt());
tx.abort();
assertEquals(TxnStatus.Aborted, tx.getStatus());
assertEquals(LOCKMODE_NONE, tranlocal.lockMode);
assertNull(tranlocal.owner);
assertEquals(initialValue, ref.long_value);
assertEquals(initialVersion, ref.getVersion());
assertCleaned(tx);
}
@Test
public void whenAborted() {
T tx = newTransaction();
tx.abort();
tx.abort();
assertEquals(TxnStatus.Aborted, tx.getStatus());
assertCleaned(tx);
}
@Test
public void whenCommitted_thenDeadTxnException() {
T tx = newTransaction();
tx.commit();
try {
tx.abort();
fail();
} catch (DeadTxnException expected) {
}
assertEquals(TxnStatus.Committed, tx.getStatus());
assertCleaned(tx);
}
}