/* * 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.tests.timing.core.server.impl; import java.util.ArrayList; import java.util.List; import org.apache.activemq.artemis.api.core.Message; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.server.HandleStatus; import org.apache.activemq.artemis.core.server.MessageReference; import org.apache.activemq.artemis.core.server.Queue; import org.apache.activemq.artemis.core.server.QueueConfig; import org.apache.activemq.artemis.core.server.impl.QueueImpl; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; import org.apache.activemq.artemis.tests.unit.core.server.impl.fakes.FakeConsumer; import org.apache.activemq.artemis.tests.unit.core.server.impl.fakes.FakeQueueFactory; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * A concurrent QueueTest * * All the concurrent queue tests go in here */ public class QueueConcurrentTest extends ActiveMQTestBase { private static final UnitTestLogger log = UnitTestLogger.LOGGER; private FakeQueueFactory queueFactory = new FakeQueueFactory(); @Override @Before public void setUp() throws Exception { super.setUp(); queueFactory = new FakeQueueFactory(); } @Override @After public void tearDown() throws Exception { queueFactory.stop(); super.tearDown(); } /* * Concurrent set consumer not busy, busy then, call deliver while messages are being added and consumed */ @Test public void testConcurrentAddsDeliver() throws Exception { QueueImpl queue = (QueueImpl) queueFactory.createQueueWith(QueueConfig.builderWith(1, new SimpleString("address1"), new SimpleString("queue1")).durable(false).temporary(false).autoCreated(false).build()); FakeConsumer consumer = new FakeConsumer(); queue.addConsumer(consumer); final long testTime = 5000; Sender sender = new Sender(queue, testTime); Toggler toggler = new Toggler(queue, consumer, testTime); sender.start(); toggler.start(); sender.join(); toggler.join(); consumer.setStatusImmediate(HandleStatus.HANDLED); queue.deliverNow(); if (sender.getException() != null) { throw sender.getException(); } if (toggler.getException() != null) { throw toggler.getException(); } assertRefListsIdenticalRefs(sender.getReferences(), consumer.getReferences()); QueueConcurrentTest.log.info("num refs: " + sender.getReferences().size()); QueueConcurrentTest.log.info("num toggles: " + toggler.getNumToggles()); } // Inner classes --------------------------------------------------------------- class Sender extends Thread { private volatile Exception e; private final Queue queue; private final long testTime; private int i; public Exception getException() { return e; } private final List<MessageReference> refs = new ArrayList<>(); public List<MessageReference> getReferences() { return refs; } Sender(final Queue queue, final long testTime) { this.testTime = testTime; this.queue = queue; } @Override public void run() { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < testTime) { Message message = generateMessage(i); MessageReference ref = MessageReference.Factory.createReference(message, queue); queue.addTail(ref, false); refs.add(ref); i++; } } } class Toggler extends Thread { private volatile Exception e; private final QueueImpl queue; private final FakeConsumer consumer; private final long testTime; private boolean toggle; private int numToggles; public int getNumToggles() { return numToggles; } public Exception getException() { return e; } Toggler(final QueueImpl queue, final FakeConsumer consumer, final long testTime) { this.testTime = testTime; this.queue = queue; this.consumer = consumer; } @Override public void run() { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < testTime) { if (toggle) { consumer.setStatusImmediate(HandleStatus.BUSY); } else { consumer.setStatusImmediate(HandleStatus.HANDLED); queue.deliverNow(); } toggle = !toggle; numToggles++; } } } }