package br.com.caelum.vraptor.jpa; import static org.mockito.Matchers.any; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import javax.enterprise.inject.spi.BeanManager; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import br.com.caelum.vraptor.controller.ControllerMethod; import br.com.caelum.vraptor.http.MutableResponse; import br.com.caelum.vraptor.interceptor.SimpleInterceptorStack; import br.com.caelum.vraptor.jpa.event.AfterCommit; import br.com.caelum.vraptor.jpa.event.AfterRollback; import br.com.caelum.vraptor.jpa.event.BeforeCommit; import br.com.caelum.vraptor.validator.Validator; public class JPATransactionInterceptorTest { @Mock private BeanManager beanManager; @Mock private EntityManager entityManager; @Mock private SimpleInterceptorStack stack; @Mock private ControllerMethod method; @Mock private EntityTransaction transaction; @Mock private Validator validator; @Mock private MutableResponse response; private JPAInterceptor interceptor; @Before public void setUp() { MockitoAnnotations.initMocks(this); interceptor = new JPATransactionInterceptor(beanManager, entityManager, validator, response); // Returns false when transaction.isActive() is called after committing the transaction. doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { when(transaction.isActive()).thenReturn(false); return null; } }).when(transaction).commit(); } @Test public void shouldStartAndCommitTransaction() throws Exception { when(entityManager.getTransaction()).thenReturn(transaction); when(transaction.isActive()).thenReturn(true); when(validator.hasErrors()).thenReturn(false); interceptor.intercept(stack); InOrder callOrder = inOrder(beanManager, entityManager, transaction, stack); callOrder.verify(entityManager).getTransaction(); callOrder.verify(transaction).begin(); callOrder.verify(stack).next(); callOrder.verify(beanManager).fireEvent(isA(BeforeCommit.class)); callOrder.verify(transaction).commit(); callOrder.verify(beanManager).fireEvent(isA(AfterCommit.class)); verify(beanManager, never()).fireEvent(isA(AfterRollback.class)); } @Test public void shouldRollbackTransactionIfStillActiveWhenExecutionFinishes() throws Exception { when(entityManager.getTransaction()).thenReturn(transaction); when(transaction.isActive()).thenReturn(true); when(validator.hasErrors()).thenReturn(true); interceptor.intercept(stack); verify(transaction).rollback(); verify(beanManager).fireEvent(isA(BeforeCommit.class)); verify(beanManager, never()).fireEvent(isA(AfterCommit.class)); verify(beanManager).fireEvent(isA(AfterRollback.class)); } @Test public void shouldRollbackIfValidatorHasErrors() { when(entityManager.getTransaction()).thenReturn(transaction); when(transaction.isActive()).thenReturn(true); when(validator.hasErrors()).thenReturn(true); interceptor.intercept(stack); verify(transaction).rollback(); verify(beanManager).fireEvent(isA(BeforeCommit.class)); verify(beanManager, never()).fireEvent(isA(AfterCommit.class)); verify(beanManager).fireEvent(isA(AfterRollback.class)); } @Test public void shouldCommitIfValidatorHasNoErrors() { when(entityManager.getTransaction()).thenReturn(transaction); when(transaction.isActive()).thenReturn(true); when(validator.hasErrors()).thenReturn(false); interceptor.intercept(stack); verify(transaction).commit(); verify(beanManager).fireEvent(isA(BeforeCommit.class)); verify(beanManager).fireEvent(isA(AfterCommit.class)); verify(beanManager, never()).fireEvent(isA(AfterRollback.class)); } @Test public void doNothingIfHasNoActiveTransation() { when(entityManager.getTransaction()).thenReturn(transaction); when(transaction.isActive()).thenReturn(false); interceptor.intercept(stack); verify(transaction, never()).rollback(); verify(transaction, never()).commit(); verify(beanManager, never()).fireEvent(isA(BeforeCommit.class)); verify(beanManager, never()).fireEvent(isA(AfterCommit.class)); verify(beanManager, never()).fireEvent(isA(AfterRollback.class)); } @Test public void shouldConfigureARedirectListenerWhenTransactionIsCommited() { when(entityManager.getTransaction()).thenReturn(transaction); when(transaction.isActive()).thenReturn(true); when(validator.hasErrors()).thenReturn(false); interceptor.intercept(stack); verify(response).addRedirectListener(any(MutableResponse.RedirectListener.class)); verify(beanManager).fireEvent(isA(BeforeCommit.class)); verify(beanManager).fireEvent(isA(AfterCommit.class)); verify(beanManager, never()).fireEvent(isA(AfterRollback.class)); } @Test public void shouldConfigureARedirectListenerWhenTransactionIsRolledback() { when(entityManager.getTransaction()).thenReturn(transaction); when(transaction.isActive()).thenReturn(true); when(validator.hasErrors()).thenReturn(true); interceptor.intercept(stack); verify(response).addRedirectListener(any(MutableResponse.RedirectListener.class)); verify(beanManager).fireEvent(isA(BeforeCommit.class)); verify(beanManager, never()).fireEvent(isA(AfterCommit.class)); verify(beanManager).fireEvent(isA(AfterRollback.class)); } }