/** * 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.broker.scheduler; import javax.jms.Connection; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.ScheduledMessage; import org.apache.activemq.util.ProducerThread; import org.apache.activemq.util.Wait; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; public class JmsSchedulerTest extends JobSchedulerTestSupport { @Test public void testCron() throws Exception { final int COUNT = 10; final AtomicInteger count = new AtomicInteger(); Connection connection = createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createConsumer(destination); final CountDownLatch latch = new CountDownLatch(COUNT); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { latch.countDown(); count.incrementAndGet(); } }); connection.start(); MessageProducer producer = session.createProducer(destination); TextMessage message = session.createTextMessage("test msg"); long time = 1000; message.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "* * * * *"); message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 500); message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, COUNT - 1); producer.send(message); producer.close(); Thread.sleep(500); SchedulerBroker sb = (SchedulerBroker) this.broker.getBroker().getAdaptor(SchedulerBroker.class); JobScheduler js = sb.getJobScheduler(); List<Job> list = js.getAllJobs(); assertEquals(1, list.size()); latch.await(240, TimeUnit.SECONDS); assertEquals(COUNT, count.get()); } @Test public void testSchedule() throws Exception { final int COUNT = 1; Connection connection = createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createConsumer(destination); final CountDownLatch latch = new CountDownLatch(COUNT); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { latch.countDown(); } }); connection.start(); long time = 5000; MessageProducer producer = session.createProducer(destination); TextMessage message = session.createTextMessage("test msg"); message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); producer.send(message); producer.close(); // make sure the message isn't delivered early Thread.sleep(2000); assertEquals(latch.getCount(), COUNT); latch.await(5, TimeUnit.SECONDS); assertEquals(latch.getCount(), 0); } @Test public void testTransactedSchedule() throws Exception { final int COUNT = 1; Connection connection = createConnection(); final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); MessageConsumer consumer = session.createConsumer(destination); final CountDownLatch latch = new CountDownLatch(COUNT); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { try { session.commit(); } catch (JMSException e) { e.printStackTrace(); } latch.countDown(); } }); connection.start(); long time = 5000; MessageProducer producer = session.createProducer(destination); TextMessage message = session.createTextMessage("test msg"); message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); producer.send(message); session.commit(); producer.close(); // make sure the message isn't delivered early Thread.sleep(2000); assertEquals(latch.getCount(), COUNT); latch.await(5, TimeUnit.SECONDS); assertEquals(latch.getCount(), 0); } @Test public void testScheduleRepeated() throws Exception { final int NUMBER = 10; final AtomicInteger count = new AtomicInteger(); Connection connection = createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createConsumer(destination); final CountDownLatch latch = new CountDownLatch(NUMBER); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { latch.countDown(); count.incrementAndGet(); } }); connection.start(); MessageProducer producer = session.createProducer(destination); TextMessage message = session.createTextMessage("test msg"); long time = 1000; message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 500); message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, NUMBER - 1); producer.send(message); producer.close(); assertEquals(latch.getCount(), NUMBER); latch.await(10, TimeUnit.SECONDS); assertEquals(0, latch.getCount()); // wait a little longer - make sure we only get NUMBER of replays Thread.sleep(1000); assertEquals(NUMBER, count.get()); } @Test public void testScheduleRestart() throws Exception { // send a message Connection connection = createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); connection.start(); MessageProducer producer = session.createProducer(destination); TextMessage message = session.createTextMessage("test msg"); long time = 5000; message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); producer.send(message); producer.close(); //restart broker broker.stop(); broker.waitUntilStopped(); broker = createBroker(false); broker.start(); broker.waitUntilStarted(); // consume the message connection = createConnection(); connection.start(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createConsumer(destination); Message msg = consumer.receive(5000); assertNotNull("Didn't receive the message", msg); //send another message producer = session.createProducer(destination); message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); producer.send(message); producer.close(); } @Test public void testJobSchedulerStoreUsage() throws Exception { // Shrink the store limit down so we get the producer to block broker.getSystemUsage().getJobSchedulerUsage().setLimit(10 * 1024); ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost"); Connection conn = factory.createConnection(); conn.start(); Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); final long time = 5000; final ProducerThread producer = new ProducerThread(sess, destination) { @Override protected Message createMessage(int i) throws Exception { Message message = super.createMessage(i); message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time); return message; } }; producer.setMessageCount(100); producer.start(); MessageConsumer consumer = sess.createConsumer(destination); final CountDownLatch latch = new CountDownLatch(100); consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { latch.countDown(); } }); // wait for the producer to block, which should happen immediately, and also wait long // enough for the delay to elapse. We should see no deliveries as the send should block // on the first message. Thread.sleep(10000L); assertEquals(100, latch.getCount()); // Increase the store limit so the producer unblocks. Everything should enqueue at this point. broker.getSystemUsage().getJobSchedulerUsage().setLimit(1024 * 1024 * 33); // Wait long enough that the messages are enqueued and the delivery delay has elapsed. Thread.sleep(10000L); // Make sure we sent all the messages we expected to send Wait.waitFor(new Wait.Condition() { @Override public boolean isSatisified() throws Exception { return producer.getSentCount() == producer.getMessageCount(); } }, 20000L); assertEquals("Producer didn't send all messages", producer.getMessageCount(), producer.getSentCount()); // Make sure we got all the messages we expected to get latch.await(20000L, TimeUnit.MILLISECONDS); assertEquals("Consumer did not receive all messages.", 0, latch.getCount()); } }