/*
* 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.tck.core.util.queue;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.mule.runtime.core.util.concurrent.Latch;
import org.mule.runtime.core.util.queue.AbstractQueueManager;
import org.mule.runtime.core.util.queue.DefaultQueueConfiguration;
import org.mule.runtime.core.util.queue.Queue;
import org.mule.runtime.core.util.queue.QueueManager;
import org.mule.runtime.core.util.queue.QueueSession;
import org.mule.tck.junit4.AbstractMuleContextTestCase;
import java.io.Serializable;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractTransactionQueueManagerTestCase extends AbstractMuleContextTestCase {
public static final int THREAD_EXECUTION_TIMEOUT = 2000;
/**
* logger used by this class
*/
protected transient Logger logger = LoggerFactory.getLogger(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(() -> {
try {
QueueSession s1 = mgr.getQueueSession();
Queue q1 = s1.getQueue("queue1");
putExecutionLatch.release();
q1.put("String1");
} catch (Exception e) {
// unlikely to happen. But if it does lets show it in the test logs.
logger.warn("Error using queue session", 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");
assertThat("Queue size", q.size(), is(0));
assertThat(q.offer("String1", 0L), is(true));
assertThat("Queue size", q.size(), is(1));
assertThat(q.offer("String2", 1000), is(false));
assertThat("Queue size", q.size(), is(1));
final Latch takeExecutionLatch = new Latch();
final Thread takeExecutionThread = new Thread(() -> {
try {
takeExecutionLatch.release();
QueueSession s1 = mgr.getQueueSession();
Queue q1 = s1.getQueue("queue1");
assertThat("Queue content", q1.take(), is("String1"));
} catch (Exception e) {
// unlikely to happen. But if it does lets show it in the test logs.
logger.warn("Error using queue session", e);
}
});
takeExecutionThread.start();
if (!takeExecutionLatch.await(THREAD_EXECUTION_TIMEOUT, TimeUnit.MILLISECONDS)) {
fail("Thread executing put over queue was not executed");
}
assertThat(q.offer("String2", 1000), is(true));
takeExecutionThread.join(THREAD_EXECUTION_TIMEOUT);
assertThat("Queue size", q.size(), is(1));
} 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 = 50;
// 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 = 50;
// 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);
}
}