package com.smartitengineering.cms.repo.dao.impl.tx;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.smartitengineering.cms.repo.dao.tx.Transaction;
import com.smartitengineering.cms.repo.dao.tx.TransactionException;
import com.smartitengineering.cms.repo.dao.tx.TransactionManager;
import com.smartitengineering.cms.repo.dao.tx.Transactional;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.Sequence;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
*
* @author imyousuf
*/
public class TransactionalInterceptorTest {
public static class TransactionalSampleUse {
@Transactional(propagationRequired = false)
public void singleTransactionWithoutPropagation() {
}
@Transactional(isolated = true)
public void singleTransactionWithIsolation() {
}
@Transactional(isolated = false)
public void singleTransactionWithNonIsolation() {
}
@Transactional
public void nestedTransactionWithNonPropagation() {
singleTransactionWithoutPropagation();
}
@Transactional
public void nestedTransactionWithPropagation() {
singleTransactionWithIsolation();
}
public void nonTransactional() {
}
}
private final Method propagtedIsolatedTransaction;
private final Method propagtedNonIsolatedTransaction;
private final Method propagtedIsolatedNestedTransaction;
private final Method nonPropagtedIsolatedNestedTransaction;
private final Method nonTransaction;
private final TransactionalSampleUse sampleService;
private Mockery mockery;
private TransactionManager mockManager;
private Injector injector;
private TransactionalInterceptor interceptor;
public TransactionalInterceptorTest() {
try {
propagtedIsolatedTransaction = TransactionalSampleUse.class.getDeclaredMethod("singleTransactionWithIsolation");
propagtedNonIsolatedTransaction = TransactionalSampleUse.class.getDeclaredMethod(
"singleTransactionWithNonIsolation");
propagtedIsolatedNestedTransaction = TransactionalSampleUse.class.getDeclaredMethod(
"nestedTransactionWithPropagation");
nonPropagtedIsolatedNestedTransaction = TransactionalSampleUse.class.getDeclaredMethod(
"singleTransactionWithoutPropagation");
nonTransaction = TransactionalSampleUse.class.getDeclaredMethod("nonTransactional");
sampleService = new TransactionalSampleUse();
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
@Before
public void setup() {
mockery = new Mockery();
mockManager = mockery.mock(TransactionManager.class);
injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(TransactionManager.class).toInstance(mockManager);
bind(TransactionalInterceptor.class);
}
});
interceptor = injector.getInstance(TransactionalInterceptor.class);
}
@Test
public void testNullMethod() throws Throwable {
final MethodInvocation invocation = mockery.mock(MethodInvocation.class);
mockery.checking(new Expectations() {
{
exactly(1).of(invocation).getMethod();
will(returnValue(null));
}
});
interceptor.invoke(invocation);
mockery.assertIsSatisfied();
}
@Test
public void testNullAnnotation() throws Throwable {
final MethodInvocation invocation = mockery.mock(MethodInvocation.class);
mockery.checking(new Expectations() {
{
exactly(1).of(invocation).getMethod();
will(returnValue(nonTransaction));
exactly(1).of(invocation).proceed();
will(returnValue(sampleService));
}
});
Assert.assertSame(sampleService, interceptor.invoke(invocation));
mockery.assertIsSatisfied();
}
@Test
public void testNewTransactionWithSuccess() throws Throwable {
final MethodInvocation invocation = mockery.mock(MethodInvocation.class);
mockery.checking(new Expectations() {
{
Sequence seq = mockery.sequence("newTx");
exactly(1).of(invocation).getMethod();
will(returnValue(propagtedIsolatedTransaction));
inSequence(seq);
exactly(1).of(mockManager).getCurrentTransaction();
will(returnValue(null));
inSequence(seq);
Transaction tx = mockery.mock(Transaction.class);
exactly(1).of(mockManager).beginTransaction(true);
will(returnValue(tx));
inSequence(seq);
exactly(1).of(invocation).proceed();
will(returnValue(sampleService));
inSequence(seq);
exactly(1).of(tx).commit();
inSequence(seq);
}
});
Assert.assertSame(sampleService, interceptor.invoke(invocation));
mockery.assertIsSatisfied();
}
@Test(expected = TransactionException.class)
public void testNewTransactionWithError() throws Throwable {
final MethodInvocation invocation = mockery.mock(MethodInvocation.class);
mockery.checking(new Expectations() {
{
Sequence seq = mockery.sequence("newTxWithError");
exactly(1).of(invocation).getMethod();
will(returnValue(propagtedIsolatedTransaction));
inSequence(seq);
exactly(1).of(mockManager).getCurrentTransaction();
will(returnValue(null));
inSequence(seq);
Transaction tx = mockery.mock(Transaction.class);
exactly(1).of(mockManager).beginTransaction(true);
will(returnValue(tx));
inSequence(seq);
exactly(1).of(invocation).proceed();
will(throwException(new TransactionException(new NullPointerException())));
inSequence(seq);
exactly(1).of(tx).rollback();
inSequence(seq);
}
});
try {
interceptor.invoke(invocation);
}
finally {
mockery.assertIsSatisfied();
}
}
@Test
public void testNewNonIsolatedTransactionWithSuccess() throws Throwable {
final MethodInvocation invocation = mockery.mock(MethodInvocation.class);
mockery.checking(new Expectations() {
{
Sequence seq = mockery.sequence("newTx");
exactly(1).of(invocation).getMethod();
will(returnValue(propagtedNonIsolatedTransaction));
inSequence(seq);
exactly(1).of(mockManager).getCurrentTransaction();
will(returnValue(null));
inSequence(seq);
Transaction tx = mockery.mock(Transaction.class);
exactly(1).of(mockManager).beginTransaction(false);
will(returnValue(tx));
inSequence(seq);
exactly(1).of(invocation).proceed();
will(returnValue(sampleService));
inSequence(seq);
exactly(1).of(tx).commit();
inSequence(seq);
}
});
Assert.assertSame(sampleService, interceptor.invoke(invocation));
mockery.assertIsSatisfied();
}
@Test
public void testNestedTransactionWithoutPropagationWithSuccess() throws Throwable {
final MethodInvocation invocation = mockery.mock(MethodInvocation.class);
mockery.checking(new Expectations() {
{
Sequence seq = mockery.sequence("newTx");
Transaction tx = mockery.mock(Transaction.class, "tx0");
exactly(1).of(mockManager).beginTransaction(true);
will(returnValue(tx));
inSequence(seq);
exactly(1).of(invocation).getMethod();
will(returnValue(nonPropagtedIsolatedNestedTransaction));
inSequence(seq);
exactly(1).of(mockManager).getCurrentTransaction();
will(returnValue(tx));
inSequence(seq);
Transaction tx1 = mockery.mock(Transaction.class, "tx1");
exactly(1).of(mockManager).beginTransaction(true);
will(returnValue(tx1));
inSequence(seq);
exactly(1).of(invocation).proceed();
will(returnValue(sampleService));
inSequence(seq);
exactly(1).of(tx1).commit();
inSequence(seq);
exactly(1).of(tx).commit();
inSequence(seq);
}
});
TransactionManager manager = injector.getInstance(TransactionManager.class);
Transaction tx = manager.beginTransaction(true);
try {
Assert.assertSame(sampleService, interceptor.invoke(invocation));
}
finally {
tx.commit();
}
mockery.assertIsSatisfied();
}
@Test
public void testNestedTransactionWithPropagationWithSuccess() throws Throwable {
final MethodInvocation invocation = mockery.mock(MethodInvocation.class);
mockery.checking(new Expectations() {
{
Sequence seq = mockery.sequence("newTx");
Transaction tx = mockery.mock(Transaction.class, "tx0");
exactly(1).of(mockManager).beginTransaction(true);
will(returnValue(tx));
inSequence(seq);
exactly(1).of(invocation).getMethod();
will(returnValue(propagtedIsolatedNestedTransaction));
inSequence(seq);
exactly(1).of(mockManager).getCurrentTransaction();
will(returnValue(tx));
inSequence(seq);
exactly(1).of(invocation).proceed();
will(returnValue(sampleService));
inSequence(seq);
exactly(1).of(tx).commit();
inSequence(seq);
}
});
TransactionManager manager = injector.getInstance(TransactionManager.class);
Transaction tx = manager.beginTransaction(true);
try {
Assert.assertSame(sampleService, interceptor.invoke(invocation));
}
finally {
tx.commit();
}
mockery.assertIsSatisfied();
}
}