/*
* 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.util.queue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.mule.tck.junit4.AbstractMuleContextTestCase;
import org.mule.util.concurrent.Latch;
import java.io.Serializable;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
public abstract class AbstractTransactionQueueManagerTestCase extends AbstractMuleContextTestCase
{
public static final int THREAD_EXECUTION_TIMEOUT = 2000;
/**
* logger used by this class
*/
protected transient Log logger = LogFactory.getLog(getClass());
protected QueueTestComponent disposeTest = new QueueTestComponent();
protected abstract AbstractQueueManager createQueueManager() throws Exception;
protected abstract boolean isPersistent();
@Test
public void testPutTake() throws Exception
{
QueueManager mgr = createQueueManager();
mgr.start();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
q.put("String1");
assertEquals("Queue size", 1, q.size());
Object o = q.take();
assertNotNull(o);
assertEquals("Queue content", "String1", o);
assertEquals("Queue size", 0, q.size());
mgr.stop();
}
@Test
public void testTakePut() throws Exception
{
final QueueManager mgr = createQueueManager();
mgr.start();
final Latch latch = new Latch();
Thread t = new Thread()
{
@Override
public void run()
{
try
{
latch.countDown();
Thread.sleep(200);
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
q.put("String1");
}
catch (Exception e)
{
// ignore, let test fail
}
}
};
t.start();
latch.await();
long t0 = System.currentTimeMillis();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
Object o = q.take();
long t1 = System.currentTimeMillis();
t.join();
assertNotNull(o);
assertEquals("Queue content", "String1", o);
assertEquals("Queue size", 0, q.size());
assertTrue(t1 - t0 > 100);
mgr.stop();
}
@Test
public void testPutTakeUntake() throws Exception
{
final QueueManager mgr = createQueueManager();
mgr.start();
final Latch latch = new Latch();
Thread t = new Thread()
{
@Override
public void run()
{
try
{
latch.countDown();
Thread.sleep(200);
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
q.put("String1");
q.put("String2");
}
catch (Exception e)
{
// ignore, let test fail
}
}
};
t.start();
latch.await();
long t0 = System.currentTimeMillis();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
Serializable o = q.take();
long t1 = System.currentTimeMillis();
t.join();
assertNotNull(o);
assertEquals("Queue content", "String1", o);
assertEquals("Queue size", 1, q.size());
assertTrue(t1 - t0 > 100);
// Same as put/take until now, but now we do an untake
q.untake(o);
// Ensure queue size is now 2
assertEquals("Queue size", 2, q.size());
// Take to ensure order is correct
Object o2 = q.take();
assertEquals("Queue content", "String1", o2);
assertEquals("Queue size", 1, q.size());
mgr.stop();
}
@Test
public void testClearWithoutTransaction() throws Exception
{
final QueueManager mgr = createQueueManager();
mgr.start();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
q.put("String1");
assertEquals("Queue size", 1, q.size());
q.clear();
assertEquals("Queue size", 0, q.size());
mgr.stop();
}
@Test
public void testClearInTransaction() throws Exception
{
final QueueManager mgr = createQueueManager();
mgr.start();
QueueSession s = mgr.getQueueSession();
// insert item in transaction
s.begin();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
q.put("String1");
s.commit();
assertEquals("Queue size", 1, q.size());
// clear queue but rollback
s.begin();
assertEquals("Queue size", 1, q.size());
q.clear();
s.rollback();
assertEquals("Queue size", 1, q.size());
// do clear in transaction
s.begin();
assertEquals("Queue size", 1, q.size());
q.clear();
s.commit();
assertEquals("Queue size", 0, q.size());
mgr.stop();
}
@Test
public void testTakePutRollbackPut() throws Exception
{
final QueueManager mgr = createQueueManager();
mgr.start();
final Latch latch = new Latch();
Thread t = new Thread()
{
@Override
public void run()
{
try
{
latch.countDown();
Thread.sleep(200);
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
s.begin();
q.put("String1");
s.rollback();
s.begin();
q.put("String2");
s.commit();
}
catch (Exception e)
{
// ignore, let test fail
}
}
};
t.start();
latch.await();
long t0 = System.currentTimeMillis();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
Object o = q.take();
long t1 = System.currentTimeMillis();
t.join();
assertNotNull(o);
assertEquals("Queue content", "String2", o);
assertEquals("Queue size", 0, q.size());
assertTrue(t1 - t0 > 100);
mgr.stop();
}
@Test
public void testPutTakeUntakeRollbackUntake() throws Exception
{
final QueueManager mgr = createQueueManager();
mgr.start();
final Latch latch = new Latch();
final Serializable object1 = "string1";
final Serializable object2 = "string2";
Thread t = new Thread()
{
@Override
public void run()
{
try
{
latch.countDown();
Thread.sleep(200);
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
s.begin();
q.untake(object1);
s.commit();
s.begin();
q.untake(object2);
s.rollback();
}
catch (Exception e)
{
// ignore, let test fail
}
}
};
t.start();
latch.await();
long t0 = System.currentTimeMillis();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
Object o = q.take();
long t1 = System.currentTimeMillis();
t.join();
assertNotNull(o);
assertEquals("Queue content", object1, o);
assertEquals("Queue size", 0, q.size());
assertTrue(t1 - t0 > 100);
mgr.stop();
}
@Test
public void testTakePutOverCapacity() throws Exception
{
final QueueManager mgr = createQueueManager();
mgr.start();
mgr.setDefaultQueueConfiguration(new DefaultQueueConfiguration(2, false));
final Latch latch = new Latch();
Thread t = new Thread()
{
@Override
public void run()
{
try
{
latch.await();
Thread.sleep(200);
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
Object o = q.take();
assertEquals("Queue content", "String1", o);
}
catch (Exception e)
{
// ignore, let test fail
}
}
};
t.start();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
q.put("String1");
q.put("String2");
latch.countDown();
long t0 = System.currentTimeMillis();
q.put("String3");
long t1 = System.currentTimeMillis();
t.join();
assertEquals("Queue size", 2, q.size());
assertTrue(t1 - t0 > 100);
mgr.stop();
}
@Test
public void testPutWithPersistence() throws Exception
{
if (isPersistent())
{
AbstractQueueManager mgr = createQueueManager();
try
{
QueueSession s = mgr.getQueueSession();
mgr.start();
Queue q = s.getQueue("queue1");
q.put("String1");
assertEquals("Queue size", 1, q.size());
q = s.getQueue("queue1");
assertEquals("Queue size", 1, q.size());
}
finally
{
mgr.stop();
mgr.dispose();
}
mgr = createQueueManager();
try
{
QueueSession s = mgr.getQueueSession();
mgr.start();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 1, q.size());
}
finally
{
mgr.stop();
mgr.dispose();
}
}
else
{
logger.info("Ignoring test because queue manager is not persistent");
}
}
@Test
public void testTransactedPutCommitWithPersistence() throws Exception
{
if (isPersistent())
{
AbstractQueueManager mgr = createQueueManager();
try
{
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
mgr.start();
s.begin();
q.put("String1");
assertEquals("Queue size", 1, q.size());
s.commit();
assertEquals("Queue size", 1, q.size());
s = mgr.getQueueSession();
q = s.getQueue("queue1");
assertEquals("Queue size", 1, q.size());
mgr.stop();
mgr = createQueueManager();
s = mgr.getQueueSession();
q = s.getQueue("queue1");
mgr.start();
assertEquals("Queue size", 1, q.size());
}
finally
{
mgr.stop();
mgr.dispose();
}
}
else
{
logger.info("Ignoring test because queue manager is not persistent");
}
}
@Test
public void testTransactedPutRollbackWithPersistence() throws Exception
{
if (isPersistent())
{
AbstractQueueManager mgr = createQueueManager();
try
{
mgr.start();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
s.begin();
q.put("String1");
assertEquals("Queue size", 1, q.size());
s.rollback();
assertEquals("Queue size", 0, q.size());
s = mgr.getQueueSession();
q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
mgr.stop();
mgr = createQueueManager();
mgr.start();
s = mgr.getQueueSession();
q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
}
finally
{
mgr.stop();
mgr.dispose();
}
}
else
{
logger.info("Ignoring test because queue manager is not persistent");
}
}
@Test
public void testPutTake_RespectsOrderOnPersistence() throws Exception
{
if (isPersistent())
{
AbstractQueueManager mgr1 = createQueueManager();
QueueSession s1 = mgr1.getQueueSession();
Queue q1 = s1.getQueue("queue1");
mgr1.start();
assertEquals("Queue size", 0, q1.size());
final int numberOfElements = 10;
for (int i = 1; i <= numberOfElements; i++)
{
q1.put("String" + i);
assertEquals("Queue size", i, q1.size());
}
mgr1.stop();
AbstractQueueManager mgr2 = createQueueManager();
QueueSession s2 = mgr2.getQueueSession();
Queue q2 = s2.getQueue("queue1");
mgr2.start();
for (int i = 1; i <= numberOfElements; i++)
{
Object o = q2.take();
assertNotNull(o);
assertEquals("Queue content", "String" + i, o);
}
assertEquals("Queue size", 0, q2.size());
mgr2.stop();
mgr2.dispose();
}
}
@Test
public void testTransactionsOnMultipleQueues() throws Exception
{
AbstractQueueManager mgr = createQueueManager();
try
{
mgr.start();
QueueSession s1 = mgr.getQueueSession();
QueueSession s2 = mgr.getQueueSession();
Queue q1s1 = s1.getQueue("queue1");
Queue q1s2 = s2.getQueue("queue1");
Queue q2s1 = s1.getQueue("queue2");
Queue q2s2 = s2.getQueue("queue2");
q1s1.put("String1");
assertEquals("Queue size", 1, q1s1.size());
assertEquals("Queue size", 1, q1s2.size());
s1.begin();
Object o = q1s1.take();
assertNotNull(o);
assertEquals("String1", o);
assertEquals("Queue size", 0, q1s1.size());
assertEquals("Queue size", 0, q1s2.size());
q2s1.put("String2");
assertEquals("Queue size", 1, q2s1.size());
assertEquals("Queue size", 0, q2s2.size());
s1.commit();
assertEquals("Queue size", 0, q1s1.size());
assertEquals("Queue size", 0, q1s2.size());
assertEquals("Queue size", 1, q2s1.size());
assertEquals("Queue size", 1, q2s2.size());
s1.begin();
o = q2s1.take();
assertNotNull(o);
assertEquals("String2", o);
assertEquals("Queue size", 0, q1s1.size());
assertEquals("Queue size", 0, q1s2.size());
assertEquals("Queue size", 0, q2s1.size());
assertEquals("Queue size", 0, q2s2.size());
q1s1.put("String1");
assertEquals("Queue size", 1, q1s1.size());
assertEquals("Queue size", 0, q1s2.size());
assertEquals("Queue size", 0, q2s1.size());
assertEquals("Queue size", 0, q2s2.size());
s1.rollback();
assertEquals("Queue size", 0, q1s1.size());
assertEquals("Queue size", 0, q1s2.size());
assertEquals("Queue size", 1, q2s1.size());
assertEquals("Queue size", 1, q2s2.size());
}
finally
{
mgr.stop();
mgr.dispose();
}
}
@Test
public void testPoll() throws Exception
{
final QueueManager mgr = createQueueManager();
try
{
mgr.start();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
Object o = q.poll(0);
assertEquals("Queue size", 0, q.size());
assertNull(o);
o = q.poll(1000);
assertEquals("Queue size", 0, q.size());
assertNull(o);
q.put("String1");
assertEquals("Queue size", 1, q.size());
o = q.poll(0);
assertEquals("Queue size", 0, q.size());
assertEquals("Queue content", "String1", o);
final Latch putExecutionLatch = new Latch();
Thread putExecutionThread = new Thread(new Runnable()
{
public void run()
{
try
{
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
putExecutionLatch.release();
q.put("String1");
}
catch (Exception e)
{
//unlikely to happen. But if it does lets show it in the test logs.
logger.warn(e);
}
}
});
putExecutionThread.start();
if (!putExecutionLatch.await(THREAD_EXECUTION_TIMEOUT, TimeUnit.MILLISECONDS))
{
fail("Thread executing put over queue was not executed");
}
o = q.poll(RECEIVE_TIMEOUT);
putExecutionThread.join(THREAD_EXECUTION_TIMEOUT);
assertEquals("Queue size", q.size(), 0);
assertEquals("Queue content", "String1", o);
}
finally
{
mgr.stop();
}
}
@Test
public void testPeek() throws Exception
{
QueueManager mgr = createQueueManager();
try
{
mgr.start();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
Object o = q.peek();
assertEquals("Queue size", 0, q.size());
assertNull(o);
q.put("String1");
assertEquals("Queue size", 1, q.size());
o = q.peek();
assertEquals("Queue size", 1, q.size());
assertEquals("Queue content", "String1", o);
o = q.poll(1000);
assertEquals("Queue size", 0, q.size());
assertEquals("Queue content", "String1", o);
}
finally
{
mgr.stop();
}
}
@Test
public void testOffer() throws Exception
{
final QueueManager mgr = createQueueManager();
mgr.setDefaultQueueConfiguration(new DefaultQueueConfiguration(1, false));
try
{
mgr.start();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue size", 0, q.size());
assertTrue(q.offer("String1", 0L));
assertEquals("Queue size", 1, q.size());
assertFalse(q.offer("String2", 1000));
assertEquals("Queue size", 1, q.size());
final Latch takeExecutionLatch = new Latch();
final Thread takeExecutionThread = new Thread(new Runnable()
{
public void run()
{
try
{
takeExecutionLatch.release();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("queue1");
assertEquals("Queue content", "String1", q.take());
}
catch (Exception e)
{
//unlikely to happen. But if it does lets show it in the test logs.
logger.warn(e);
}
}
});
takeExecutionThread.start();
if (!takeExecutionLatch.await(THREAD_EXECUTION_TIMEOUT, TimeUnit.MILLISECONDS))
{
fail("Thread executing put over queue was not executed");
}
assertTrue(q.offer("String2", 1000));
takeExecutionThread.join(THREAD_EXECUTION_TIMEOUT);
assertEquals("Queue size", 1, q.size());
}
finally
{
mgr.stop();
}
}
@Test
public void testRecoverWarmRestart() throws Exception
{
QueueManager mgr = createQueueManager();
mgr.start();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("warmRecoverQueue");
int toPopulate = 500;
// Populate queue
Random rnd = new Random();
for (int j = 0; j < toPopulate; j++)
{
byte[] o = new byte[2048];
rnd.nextBytes(o);
q.put(o);
}
assertEquals(q.size(), toPopulate);
// Stop and start TransactionalQueueManager
mgr.stop();
mgr.start();
assertEquals(toPopulate, q.size());
}
@Test
public void testRecoverColdRestart() throws Exception
{
QueueManager mgr = createQueueManager();
QueueSession s = mgr.getQueueSession();
Queue q = s.getQueue("warmRecoverQueue");
mgr.start();
int toPopulate = 500;
// Populate queue
Random rnd = new Random();
for (int j = 0; j < toPopulate; j++)
{
byte[] o = new byte[2048];
rnd.nextBytes(o);
q.put(o);
}
assertEquals(toPopulate, q.size());
// Stop and recreate TransactionalQueueManager simulating a cold restart
mgr.stop();
mgr = createQueueManager();
s = mgr.getQueueSession();
q = s.getQueue("warmRecoverQueue");
mgr.start();
if (isPersistent())
{
assertEquals(toPopulate, q.size());
}
else
{
assertEquals(0, q.size());
}
}
@Test
public void testDisposeQueueWithoutTransaction() throws Exception
{
this.disposeTest.testDisposal(this.createQueueManager(), false);
}
@Test
public void testDisposeQueueInTransaction() throws Exception
{
this.disposeTest.testDisposal(this.createQueueManager(), true);
}
@Test
public void testDisposeQueueByNameInTransaction() throws Exception
{
this.disposeTest.testDisposal(this.createQueueManager(), true);
}
}