/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.transaction; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.times; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.transaction.Transaction; import org.mule.runtime.api.tx.TransactionException; import org.mule.tck.junit4.AbstractMuleTestCase; import org.mule.tck.size.SmallTest; import org.mule.tck.testmodels.mule.TestTransaction; import org.hamcrest.core.IsNull; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; @SmallTest @RunWith(MockitoJUnitRunner.class) public class TransactionCoordinationTestCase extends AbstractMuleTestCase { private MuleContext muleContext; private TransactionCoordination tc; @Before public void setUpTransaction() throws Exception { tc = TransactionCoordination.getInstance(); muleContext = mock(MuleContext.class, RETURNS_DEEP_STUBS); when(muleContext.getConfiguration().getId()).thenReturn("appName"); } @After public void unbindTransaction() throws Exception { tc.unbindTransaction(tc.getTransaction()); } @Test public void testBindTransaction() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); Transaction tx = mock(Transaction.class); tc.bindTransaction(tx); assertEquals(tx, tc.getTransaction()); tc.unbindTransaction(tx); } @Test public void testBindTransactionWithAlreadyBound() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); Transaction tx = mock(Transaction.class); tc.bindTransaction(tx); assertEquals(tx, tc.getTransaction()); try { Transaction tx2 = mock(Transaction.class); tc.bindTransaction(tx2); fail(); } catch (IllegalTransactionStateException e) { // expected } tc.unbindTransaction(tx); } @Test public void testUnbindTransactionWithoutBound() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); Transaction tx = mock(Transaction.class); tc.unbindTransaction(tx); } @Test public void testSetInstanceWithBound() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); Transaction tx = mock(Transaction.class); tc.bindTransaction(tx); tc.unbindTransaction(tx); } @Test public void testCommitCurrentTransaction() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); tc.commitCurrentTransaction(); TestTransaction testTransaction = spy(new TestTransaction(muleContext)); tc.bindTransaction(testTransaction); tc.commitCurrentTransaction(); assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); verify(testTransaction, times(1)).commit(); } @Test public void testCommitCurrentTransactionWithSuspendedTransaction() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); TestTransaction xaTx = spy(new TestTransaction(muleContext)); xaTx.setXA(true); Transaction tx = spy(new TestTransaction(muleContext)); tc.bindTransaction(xaTx); tc.suspendCurrentTransaction(); tc.bindTransaction(tx); tc.commitCurrentTransaction(); tc.resumeSuspendedTransaction(); assertThat((TestTransaction) tc.getTransaction(), is(xaTx)); verify(xaTx, times(1)).suspend(); verify(xaTx, times(1)).resume(); verify(tx, times(1)).commit(); } @Test public void testCommitDoesntFailOnException() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); Transaction tx = mock(Transaction.class); doThrow(new TransactionException((Throwable) null)).when(tx).commit(); TransactionCoordination.getInstance().commitCurrentTransaction(); } @Test public void testRollbackCurrentTransaction() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); tc.commitCurrentTransaction(); TestTransaction testTransaction = spy(new TestTransaction(muleContext)); tc.bindTransaction(testTransaction); tc.rollbackCurrentTransaction(); assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); verify(testTransaction, times(1)).rollback(); } @Test public void testRollbackCurrentTransactionWithSuspendedTransaction() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); TestTransaction xaTx = spy(new TestTransaction(muleContext)); xaTx.setXA(true); Transaction tx = spy(new TestTransaction(muleContext)); tc.bindTransaction(xaTx); tc.suspendCurrentTransaction(); tc.bindTransaction(tx); tc.rollbackCurrentTransaction(); tc.resumeSuspendedTransaction(); assertThat((TestTransaction) tc.getTransaction(), is(xaTx)); verify(xaTx, times(1)).suspend(); verify(xaTx, times(1)).resume(); verify(tx, times(1)).rollback(); } @Test public void testRollbackDoesntFailOnException() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); Transaction tx = mock(Transaction.class); doThrow(new TransactionException((Throwable) null)).when(tx).rollback(); TransactionCoordination.getInstance().rollbackCurrentTransaction(); } @Test public void testSuspendResumeTransaction() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); Transaction tx = mock(Transaction.class); tc.bindTransaction(tx); tc.suspendCurrentTransaction(); assertNull(tc.getTransaction()); tc.resumeSuspendedTransaction(); verify(tx, times(1)).suspend(); verify(tx, times(1)).resume(); assertThat(tc.getTransaction(), is(tx)); } @Test public void testResumeXaTransactionIfAvailableWithNoTx() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); tc.resumeXaTransactionIfAvailable(); Transaction tx = spy(new TestTransaction(muleContext)); tc.bindTransaction(tx); tc.resumeXaTransactionIfAvailable(); verify(tx, times(0)).resume(); } @Test public void testResumeXaTransactionIfAvailableWithTx() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); tc.resumeXaTransactionIfAvailable(); TestTransaction tx = spy(new TestTransaction(muleContext)); tx.setXA(true); tc.bindTransaction(tx); tc.suspendCurrentTransaction(); tc.resumeXaTransactionIfAvailable(); verify(tx, times(1)).suspend(); verify(tx, times(1)).resume(); } @Test(expected = IllegalTransactionStateException.class) public void testResumeXaTransactionTwice() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); TestTransaction tx = spy(new TestTransaction(muleContext)); tx.setXA(true); tc.bindTransaction(tx); tc.resumeSuspendedTransaction(); tc.resumeSuspendedTransaction(); } @Test public void testResolveTransactionForRollback() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); TestTransaction tx = spy(new TestTransaction(muleContext)); tx.setXA(true); tc.bindTransaction(tx); tx.setRollbackOnly(); tc.resolveTransaction(); assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); verify(tx, times(1)).rollback(); } @Test public void testResolveTransactionForCommit() throws Exception { assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); TestTransaction tx = spy(new TestTransaction(muleContext)); tx.setXA(true); tc.bindTransaction(tx); tc.resolveTransaction(); assertThat(tc.getTransaction(), IsNull.<Object>nullValue()); verify(tx, times(1)).commit(); } }