/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.artemis.jms.tests.message;
import javax.jms.DeliveryMode;
import javax.jms.Message;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.activemq.artemis.jms.client.ActiveMQMessage;
import org.apache.activemq.artemis.jms.tests.util.ProxyAssertSupport;
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class JMSExpirationHeaderTest extends MessageHeaderTestBase {
// Constants -----------------------------------------------------
// Static --------------------------------------------------------
// Attributes ----------------------------------------------------
private volatile boolean testFailed;
private volatile long effectiveReceiveTime;
private volatile Message expectedMessage;
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
@Override
@Before
public void setUp() throws Exception {
super.setUp();
expectedMessage = null;
testFailed = false;
effectiveReceiveTime = 0;
}
@Override
@After
public void tearDown() throws Exception {
super.tearDown();
}
// Tests ---------------------------------------------------------
@Test
public void testZeroExpiration() throws Exception {
Message m = queueProducerSession.createMessage();
queueProducer.send(m);
ProxyAssertSupport.assertEquals(0, queueConsumer.receive().getJMSExpiration());
}
@Test
public void testNoExpirationOnTimeoutReceive() throws Exception {
Message m = queueProducerSession.createMessage();
queueProducer.send(m, DeliveryMode.NON_PERSISTENT, 4, 5000);
// DeliveryImpl is asynch - need to give enough time to get to the consumer
Thread.sleep(2000);
Message result = queueConsumer.receive(10);
ProxyAssertSupport.assertEquals(m.getJMSMessageID(), result.getJMSMessageID());
}
@Test
public void testExpirationOnTimeoutReceive() throws Exception {
Message m = queueProducerSession.createMessage();
queueProducer.send(m, DeliveryMode.NON_PERSISTENT, 4, 1000);
// DeliveryImpl is asynch - need to give enough time to get to the consumer
Thread.sleep(2000);
ProxyAssertSupport.assertNull(queueConsumer.receive(100));
}
@Test
public void testExpirationOnReceiveNoWait() throws Exception {
Message m = queueProducerSession.createMessage();
queueProducer.send(m, DeliveryMode.NON_PERSISTENT, 4, 1000);
// DeliveryImpl is asynch - need to give enough time to get to the consumer
Thread.sleep(2000);
ProxyAssertSupport.assertNull(queueConsumer.receiveNoWait());
}
@Test
public void testExpiredMessageDiscardingOnTimeoutReceive() throws Exception {
Message m = queueProducerSession.createMessage();
queueProducer.send(m, DeliveryMode.NON_PERSISTENT, 4, 1000);
// DeliveryImpl is asynch - need to give enough time to get to the consumer
Thread.sleep(2000);
// start the receiver thread
final CountDownLatch latch = new CountDownLatch(1);
Thread receiverThread = new Thread(new Runnable() {
@Override
public void run() {
try {
expectedMessage = queueConsumer.receive(100);
} catch (Exception e) {
log.trace("receive() exits with an exception", e);
} finally {
latch.countDown();
}
}
}, "receiver thread");
receiverThread.start();
ActiveMQTestBase.waitForLatch(latch);
ProxyAssertSupport.assertNull(expectedMessage);
}
@Test
public void testReceiveTimeoutPreservation() throws Exception {
final long timeToWaitForReceive = 5000;
final CountDownLatch receiverLatch = new CountDownLatch(1);
// start the receiver thread
Thread receiverThread = new Thread(new Runnable() {
@Override
public void run() {
try {
long t1 = System.currentTimeMillis();
expectedMessage = queueConsumer.receive(timeToWaitForReceive);
effectiveReceiveTime = System.currentTimeMillis() - t1;
} catch (Exception e) {
log.trace("receive() exits with an exception", e);
} finally {
receiverLatch.countDown();
}
}
}, "receiver thread");
receiverThread.start();
final CountDownLatch senderLatch = new CountDownLatch(1);
// start the sender thread
Thread senderThread = new Thread(new Runnable() {
@Override
public void run() {
try {
// wait for 3 secs
Thread.sleep(3000);
// send an expired message
Message m = queueProducerSession.createMessage();
queueProducer.send(m, DeliveryMode.NON_PERSISTENT, 4, -1);
ActiveMQMessage msg = (ActiveMQMessage) m;
if (!msg.getCoreMessage().isExpired()) {
log.error("The message " + m + " should have expired");
testFailed = true;
return;
}
} catch (Exception e) {
log.error("This exception will fail the test", e);
testFailed = true;
} finally {
senderLatch.countDown();
}
}
}, "sender thread");
senderThread.start();
ActiveMQTestBase.waitForLatch(senderLatch);
ActiveMQTestBase.waitForLatch(receiverLatch);
if (testFailed) {
ProxyAssertSupport.fail("Test failed by the sender thread. Watch for exception in logs");
}
log.trace("planned waiting time: " + timeToWaitForReceive + " effective waiting time " + effectiveReceiveTime);
ProxyAssertSupport.assertTrue(effectiveReceiveTime >= timeToWaitForReceive);
ProxyAssertSupport.assertTrue(effectiveReceiveTime < timeToWaitForReceive * 1.5); // well, how exactly I did come
// up with this coeficient is
// not clear even to me, I just
// noticed that if I use 1.01
// this assertion sometimes
// fails;
ProxyAssertSupport.assertNull(expectedMessage);
}
@Test
public void testNoExpirationOnReceive() throws Exception {
Message m = queueProducerSession.createMessage();
queueProducer.send(m, DeliveryMode.NON_PERSISTENT, 4, 5000);
Message result = queueConsumer.receive();
ProxyAssertSupport.assertEquals(m.getJMSMessageID(), result.getJMSMessageID());
}
@Test
public void testExpirationOnReceive() throws Exception {
final AtomicBoolean received = new AtomicBoolean(true);
queueProducer.send(queueProducerSession.createMessage(), DeliveryMode.NON_PERSISTENT, 4, 2000);
// allow the message to expire
Thread.sleep(3000);
// When a consumer is closed while a receive() is in progress it will make the
// receive return with null
final CountDownLatch latch = new CountDownLatch(1);
// blocking read for a while to make sure I don't get anything, not even a null
Thread receiverThread = new Thread(new Runnable() {
@Override
public void run() {
try {
log.trace("Attempting to receive");
expectedMessage = queueConsumer.receive();
// NOTE on close, the receive() call will return with null
log.trace("Receive exited without exception:" + expectedMessage);
if (expectedMessage == null) {
received.set(false);
}
} catch (Exception e) {
log.trace("receive() exits with an exception", e);
ProxyAssertSupport.fail();
} catch (Throwable t) {
log.trace("receive() exits with a throwable", t);
ProxyAssertSupport.fail();
} finally {
latch.countDown();
}
}
}, "receiver thread");
receiverThread.start();
Thread.sleep(3000);
// receiverThread.interrupt();
queueConsumer.close();
// wait for the reading thread to conclude
ActiveMQTestBase.waitForLatch(latch);
log.trace("Expected message:" + expectedMessage);
ProxyAssertSupport.assertFalse(received.get());
}
/*
* Need to make sure that expired messages are acked so they get removed from the
* queue/subscription, when delivery is attempted
*/
@Test
public void testExpiredMessageDoesNotGoBackOnQueue() throws Exception {
Message m = queueProducerSession.createMessage();
m.setStringProperty("weebles", "wobble but they don't fall down");
queueProducer.send(m, DeliveryMode.NON_PERSISTENT, 4, 1000);
// DeliveryImpl is asynch - need to give enough time to get to the consumer
Thread.sleep(2000);
ProxyAssertSupport.assertNull(queueConsumer.receive(100));
// Need to check message isn't still in queue
checkEmpty(queue1);
}
// Package protected ---------------------------------------------
// Protected -----------------------------------------------------
// Private -------------------------------------------------------
// Inner classes -------------------------------------------------
}