package org.skyscreamer.nevado.jms.facilities; import junit.framework.Assert; import org.junit.Test; import org.skyscreamer.nevado.jms.AbstractJMSTest; import org.skyscreamer.nevado.jms.NevadoSession; import org.skyscreamer.nevado.jms.message.NevadoMessage; import org.skyscreamer.nevado.jms.message.NevadoTextMessage; import org.skyscreamer.nevado.jms.message.TestBrokenMessage; import org.skyscreamer.nevado.jms.util.RandomData; import javax.jms.*; import javax.jms.IllegalStateException; /** * Tests transactional behavior for sessions, per JMS 1.1 Sec. 4.4.7 * * @author Carter Page <carter@skyscreamer.org> */ public class SessionTransactionTest extends AbstractJMSTest { @Test public void testTransaction() throws JMSException, InterruptedException { Session controlSession = createSession(); // Create a couple of temporary queues for the test Queue queue1 = controlSession.createTemporaryQueue(); Queue queue2 = controlSession.createTemporaryQueue(); // Put some messages in a queue TextMessage ctlMsg1 = controlSession.createTextMessage(RandomData.readString()); TextMessage ctlMsg2 = controlSession.createTextMessage(RandomData.readString()); TextMessage ctlMsg3 = controlSession.createTextMessage(RandomData.readString()); // Send some messages non-transactionally to queue #1 MessageProducer nonTxProducer = controlSession.createProducer(queue1); nonTxProducer.send(ctlMsg1); nonTxProducer.send(ctlMsg2); nonTxProducer.send(ctlMsg3); // Read some messages with a transactional session from queue #1 Session txSession = getConnection().createSession(true, Session.SESSION_TRANSACTED); MessageConsumer txConsumer = txSession.createConsumer(queue1); TextMessage msg1 = (NevadoTextMessage) txConsumer.receive(); TextMessage msg2 = (NevadoTextMessage) txConsumer.receive(); TextMessage msg3 = (NevadoTextMessage) txConsumer.receive(); compareTextMessages(new TextMessage[] {ctlMsg1, ctlMsg2, ctlMsg3}, new TextMessage[] {msg1, msg2, msg3}); Assert.assertNull(txConsumer.receive(100)); // Send some messages transactionally to queue #2, don't commit, rollback MessageProducer txProducer = txSession.createProducer(queue2); TextMessage rollbackMsg1 = txSession.createTextMessage(RandomData.readString()); TextMessage rollbackMsg2 = txSession.createTextMessage(RandomData.readString()); _log.info("These messages are going to be rolled back, so should never be seen again: " + rollbackMsg1 + " " + rollbackMsg2); txProducer.send(rollbackMsg1); txProducer.send(rollbackMsg2); // Read message with non-transactional consumer MessageConsumer nonTxConsumer = controlSession.createConsumer(queue2); Assert.assertNull("Messages sent in a transaction were transmitted before they were committed", nonTxConsumer.receive(100)); // Rollback transaction. This should rollback the messages we read, and the messages we sent. txSession.rollback(); // Re-receive the messages produces non-transactionally, and received transactionally (but rolled back) msg1 = (NevadoTextMessage) txConsumer.receive(); msg2 = (NevadoTextMessage) txConsumer.receive(); msg3 = (NevadoTextMessage) txConsumer.receive(); compareTextMessages(new TextMessage[] {ctlMsg1, ctlMsg2, ctlMsg3}, new TextMessage[] {msg1, msg2, msg3}); Assert.assertNull(txConsumer.receive(100)); // Re-send transactionally sent messages TextMessage commitMsg1 = txSession.createTextMessage(RandomData.readString()); TextMessage commitMsg2 = txSession.createTextMessage(RandomData.readString()); txProducer.send(commitMsg1); _log.info("Sent message without committing: " + commitMsg1); txProducer.send(commitMsg2); _log.info("Sent message without committing: " + commitMsg2); // Test that nothing has been sent yet Message msg = nonTxConsumer.receive(500); Assert.assertNull("We still haven't committed. Should be no messages yet.", msg); // Commit. This should send the messages. Check the results. Give it a little time for async connectors. txSession.commit(); Assert.assertNull(txConsumer.receive(100)); TextMessage msgOut1 = (TextMessage)nonTxConsumer.receive(1000); _log.info("Got msg: " + msgOut1); TextMessage msgOut2 = (TextMessage)nonTxConsumer.receive(1000); _log.info("Got msg: " + msgOut2); Assert.assertNull(nonTxConsumer.receive(500)); compareTextMessages(new TextMessage[] {commitMsg1, commitMsg2}, new TextMessage[] {msgOut1, msgOut2}); } @Test public void testTransactionRollbackPartialReplay() throws JMSException, InterruptedException { Session controlSession = createSession(); // Create a couple of temporary queues for the test Queue testConsumeQueue = controlSession.createTemporaryQueue(); // Put some messages in a queue and set up the listener to monitor production TextMessage ctlMsg1 = controlSession.createTextMessage(RandomData.readString()); TextMessage ctlMsg2 = controlSession.createTextMessage(RandomData.readString()); TextMessage ctlMsg3 = controlSession.createTextMessage(RandomData.readString()); MessageProducer producer = controlSession.createProducer(testConsumeQueue); producer.send(ctlMsg1); producer.send(ctlMsg2); producer.send(ctlMsg3); // Read some messages, send some messages Session txSession = getConnection().createSession(true, Session.SESSION_TRANSACTED); MessageConsumer txConsumer = txSession.createConsumer(testConsumeQueue); TextMessage msg1 = (NevadoTextMessage) txConsumer.receive(); TextMessage msg2 = (NevadoTextMessage) txConsumer.receive(); TextMessage msg3 = (NevadoTextMessage) txConsumer.receive(); compareTextMessages(new TextMessage[] {ctlMsg1, ctlMsg2, ctlMsg3}, new TextMessage[] {msg1, msg2, msg3}); Assert.assertNull(txConsumer.receive(100)); // Rollback, re-read (partially) and re-send txSession.rollback(); TextMessage rollbackMsg1 = (NevadoTextMessage) txConsumer.receive(); TextMessage rollbackMsg2 = (NevadoTextMessage) txConsumer.receive(); compareTextMessages(new TextMessage[] {msg1, msg2}, new TextMessage[] {rollbackMsg1, rollbackMsg2}); // Commit and check the results txSession.commit(); TextMessage rollbackMsg3 = (NevadoTextMessage) txConsumer.receive(500); Assert.assertEquals(msg3.getText(), rollbackMsg3.getText()); txSession.commit(); } @Test(expected = IllegalStateException.class) public void testCommitNoTx() throws JMSException { NevadoSession session = createSession(); session.commit(); } // Really nasty edge case to test sec 4.4.13, part 1 //@Test - TODO - need bulk send to work public void testAmbiguousWriteCommit() throws JMSException { NevadoSession readerSession = createSession(); NevadoSession session = getConnection().createSession(true, Session.SESSION_TRANSACTED); Queue testQueue = createTempQueue(session); NevadoMessage msg1 = session.createTextMessage(RandomData.readString()); NevadoMessage msg2 = new TestBrokenMessage(session.createTextMessage(RandomData.readString())); MessageProducer producer = session.createProducer(testQueue); producer.send(msg1); producer.send(msg2); boolean exceptionThrown = false; try { session.commit(); } catch (Throwable t) { exceptionThrown = true; } Assert.assertTrue("Bomb message didn't work", exceptionThrown); MessageConsumer consumer = readerSession.createConsumer(testQueue); Assert.assertNull("Got a message, but shouldn't have gotten one after ambiguous commit", consumer.receive(500)); session.rollback(); TextMessage msg3 = session.createTextMessage(RandomData.readString()); producer.send(msg3); session.commit(); TextMessage msgOut = (TextMessage)consumer.receive(1000); Assert.assertNotNull(msgOut); Assert.assertEquals(msg3, msgOut); } }