diff --git a/activemq-client/src/test/java/org/apache/activemq/usage/MemoryUsageConcurrencyTest.java b/activemq-client/src/test/java/org/apache/activemq/usage/MemoryUsageConcurrencyTest.java index 56a42975220..b8475fcafa5 100644 --- a/activemq-client/src/test/java/org/apache/activemq/usage/MemoryUsageConcurrencyTest.java +++ b/activemq-client/src/test/java/org/apache/activemq/usage/MemoryUsageConcurrencyTest.java @@ -40,7 +40,7 @@ public class MemoryUsageConcurrencyTest { @Test public void testCycle() throws Exception { final Random r = new Random(0xb4a14); - for (int i = 0; i < 30000; i++) { + for (int i = 0; i < 3000; i++) { checkPercentage(i, i, r.nextInt(100) + 10, i % 2 == 0, i % 5 == 0); } } diff --git a/activemq-mqtt/src/test/java/org/apache/activemq/transport/mqtt/MQTTTest.java b/activemq-mqtt/src/test/java/org/apache/activemq/transport/mqtt/MQTTTest.java index 2f22505c337..27786f6b124 100644 --- a/activemq-mqtt/src/test/java/org/apache/activemq/transport/mqtt/MQTTTest.java +++ b/activemq-mqtt/src/test/java/org/apache/activemq/transport/mqtt/MQTTTest.java @@ -1701,7 +1701,7 @@ public void testReceiveMessageSentWhileOffline() throws Exception { // ConsumerInfo asynchronously, so messages may not be ready for dispatch yet. assertTrue("Subscription should become active in run " + (j + 1), Wait.waitFor(() -> isSubscriptionActive(topics[0], mqttSub.getClientId().toString()), - TimeUnit.SECONDS.toMillis(30), 100)); + TimeUnit.SECONDS.toMillis(60), 100)); for (int i = 0; i < messagesPerRun; ++i) { Message message = connectionSub.receive(5, TimeUnit.SECONDS); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/MessageListenerRedeliveryTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/MessageListenerRedeliveryTest.java index 26222b67474..b9e4dd65555 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/MessageListenerRedeliveryTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/MessageListenerRedeliveryTest.java @@ -41,6 +41,7 @@ import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQMessage; import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.Wait; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -79,7 +80,7 @@ protected String getTestName() { } protected RedeliveryPolicy getRedeliveryPolicy() { - RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy(); + final RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy(); redeliveryPolicy.setInitialRedeliveryDelay(0); redeliveryPolicy.setRedeliveryDelay(1000); redeliveryPolicy.setMaximumRedeliveries(3); @@ -89,14 +90,14 @@ protected RedeliveryPolicy getRedeliveryPolicy() { } protected Connection createConnection() throws Exception { - ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false&marshal=true"); + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false&marshal=true"); factory.setRedeliveryPolicy(getRedeliveryPolicy()); return factory.createConnection(); } private class TestMessageListener implements MessageListener { - public int counter; + public volatile int counter; private final Session session; public TestMessageListener(Session session) { @@ -123,130 +124,88 @@ public void onMessage(Message message) { } @Test(timeout = 60000) - public void testQueueRollbackConsumerListener() throws JMSException { + public void testQueueRollbackConsumerListener() throws Exception { connection.start(); - Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); - Queue queue = session.createQueue("queue-" + getTestName()); - MessageProducer producer = createProducer(session, queue); - Message message = createTextMessage(session); + final Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + final Queue queue = session.createQueue("queue-" + getTestName()); + final MessageProducer producer = createProducer(session, queue); + final Message message = createTextMessage(session); producer.send(message); session.commit(); - MessageConsumer consumer = session.createConsumer(queue); + final MessageConsumer consumer = session.createConsumer(queue); - ActiveMQMessageConsumer mc = (ActiveMQMessageConsumer) consumer; + final ActiveMQMessageConsumer mc = (ActiveMQMessageConsumer) consumer; mc.setRedeliveryPolicy(getRedeliveryPolicy()); - TestMessageListener listener = new TestMessageListener(session); + final TestMessageListener listener = new TestMessageListener(session); consumer.setMessageListener(listener); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - } - // first try.. should get 2 since there is no delay on the // first redeliver.. - assertEquals(2, listener.counter); + assertTrue("first redelivery (counter==2)", Wait.waitFor(() -> listener.counter >= 2, 5000, 100)); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } // 2nd redeliver (redelivery after 1 sec) - assertEquals(3, listener.counter); + assertTrue("second redelivery (counter==3)", Wait.waitFor(() -> listener.counter >= 3, 5000, 100)); - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - } // 3rd redeliver (redelivery after 2 seconds) - it should give up after // that - assertEquals(4, listener.counter); + assertTrue("third redelivery (counter==4)", Wait.waitFor(() -> listener.counter >= 4, 5000, 100)); // create new message producer.send(createTextMessage(session)); session.commit(); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - } // it should be committed, so no redelivery - assertEquals(5, listener.counter); + assertTrue("committed message delivered (counter==5)", Wait.waitFor(() -> listener.counter >= 5, 5000, 100)); - try { - Thread.sleep(1500); - } catch (InterruptedException e) { - } - // no redelivery, counter should still be 4 + // no redelivery, counter should still be 5 - sleep is acceptable here + // because we are verifying that NO further redelivery occurs (negative test) + Thread.sleep(1500); assertEquals(5, listener.counter); session.close(); } @Test(timeout = 60000) - public void testQueueRollbackSessionListener() throws JMSException { + public void testQueueRollbackSessionListener() throws Exception { connection.start(); - Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); - Queue queue = session.createQueue("queue-" + getTestName()); - MessageProducer producer = createProducer(session, queue); - Message message = createTextMessage(session); + final Session session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE); + final Queue queue = session.createQueue("queue-" + getTestName()); + final MessageProducer producer = createProducer(session, queue); + final Message message = createTextMessage(session); producer.send(message); session.commit(); - MessageConsumer consumer = session.createConsumer(queue); + final MessageConsumer consumer = session.createConsumer(queue); - ActiveMQMessageConsumer mc = (ActiveMQMessageConsumer) consumer; + final ActiveMQMessageConsumer mc = (ActiveMQMessageConsumer) consumer; mc.setRedeliveryPolicy(getRedeliveryPolicy()); - TestMessageListener listener = new TestMessageListener(session); + final TestMessageListener listener = new TestMessageListener(session); consumer.setMessageListener(listener); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - - } // first try - assertEquals(2, listener.counter); - - try { - Thread.sleep(1000); - } catch (InterruptedException e) { + assertTrue("first redelivery (counter==2)", Wait.waitFor(() -> listener.counter >= 2, 5000, 100)); - } // second try (redelivery after 1 sec) - assertEquals(3, listener.counter); - - try { - Thread.sleep(2000); - } catch (InterruptedException e) { + assertTrue("second redelivery (counter==3)", Wait.waitFor(() -> listener.counter >= 3, 5000, 100)); - } // third try (redelivery after 2 seconds) - it should give up after that - assertEquals(4, listener.counter); + assertTrue("third redelivery (counter==4)", Wait.waitFor(() -> listener.counter >= 4, 5000, 100)); // create new message producer.send(createTextMessage(session)); session.commit(); - try { - Thread.sleep(500); - } catch (InterruptedException e) { - // ignore - } // it should be committed, so no redelivery - assertEquals(5, listener.counter); + assertTrue("committed message delivered (counter==5)", Wait.waitFor(() -> listener.counter >= 5, 5000, 100)); - try { - Thread.sleep(1500); - } catch (InterruptedException e) { - // ignore - } - // no redelivery, counter should still be 4 + // no redelivery, counter should still be 5 - sleep is acceptable here + // because we are verifying that NO further redelivery occurs (negative test) + Thread.sleep(1500); assertEquals(5, listener.counter); session.close(); @@ -256,37 +215,34 @@ public void testQueueRollbackSessionListener() throws JMSException { public void testQueueSessionListenerExceptionRetry() throws Exception { connection.start(); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = session.createQueue("queue-" + getTestName()); - MessageProducer producer = createProducer(session, queue); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue queue = session.createQueue("queue-" + getTestName()); + final MessageProducer producer = createProducer(session, queue); Message message = createTextMessage(session, "1"); producer.send(message); message = createTextMessage(session, "2"); producer.send(message); - MessageConsumer consumer = session.createConsumer(queue); + final MessageConsumer consumer = session.createConsumer(queue); final CountDownLatch gotMessage = new CountDownLatch(2); final AtomicInteger count = new AtomicInteger(0); final int maxDeliveries = getRedeliveryPolicy().getMaximumRedeliveries(); final ArrayList received = new ArrayList(); - consumer.setMessageListener(new MessageListener() { - @Override - public void onMessage(Message message) { - LOG.info("Message Received: " + message); - try { - received.add(((TextMessage) message).getText()); - } catch (JMSException e) { - e.printStackTrace(); - fail(e.toString()); - } - if (count.incrementAndGet() < maxDeliveries) { - throw new RuntimeException(getTestName() + " force a redelivery"); - } - // new blood - count.set(0); - gotMessage.countDown(); + consumer.setMessageListener(message1 -> { + LOG.info("Message Received: " + message1); + try { + received.add(((TextMessage) message1).getText()); + } catch (JMSException e) { + e.printStackTrace(); + fail(e.toString()); } + if (count.incrementAndGet() < maxDeliveries) { + throw new RuntimeException(getTestName() + " force a redelivery"); + } + // new blood + count.set(0); + gotMessage.countDown(); }); assertTrue("got message before retry expiry", gotMessage.await(20, TimeUnit.SECONDS)); @@ -304,37 +260,31 @@ public void onMessage(Message message) { public void testQueueSessionListenerExceptionDlq() throws Exception { connection.start(); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = session.createQueue("queue-" + getTestName()); - MessageProducer producer = createProducer(session, queue); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue queue = session.createQueue("queue-" + getTestName()); + final MessageProducer producer = createProducer(session, queue); Message message = createTextMessage(session); producer.send(message); final Message[] dlqMessage = new Message[1]; - ActiveMQDestination dlqDestination = new ActiveMQQueue("ActiveMQ.DLQ"); - MessageConsumer dlqConsumer = session.createConsumer(dlqDestination); + final ActiveMQDestination dlqDestination = new ActiveMQQueue("ActiveMQ.DLQ"); + final MessageConsumer dlqConsumer = session.createConsumer(dlqDestination); final CountDownLatch gotDlqMessage = new CountDownLatch(1); - dlqConsumer.setMessageListener(new MessageListener() { - @Override - public void onMessage(Message message) { - LOG.info("DLQ Message Received: " + message); - dlqMessage[0] = message; - gotDlqMessage.countDown(); - } + dlqConsumer.setMessageListener(msg -> { + LOG.info("DLQ Message Received: " + msg); + dlqMessage[0] = msg; + gotDlqMessage.countDown(); }); - MessageConsumer consumer = session.createConsumer(queue); + final MessageConsumer consumer = session.createConsumer(queue); final int maxDeliveries = getRedeliveryPolicy().getMaximumRedeliveries(); final CountDownLatch gotMessage = new CountDownLatch(maxDeliveries); - consumer.setMessageListener(new MessageListener() { - @Override - public void onMessage(Message message) { - LOG.info("Message Received: " + message); - gotMessage.countDown(); - throw new RuntimeException(getTestName() + " force a redelivery"); - } + consumer.setMessageListener(msg -> { + LOG.info("Message Received: " + msg); + gotMessage.countDown(); + throw new RuntimeException(getTestName() + " force a redelivery"); }); assertTrue("got message before retry expiry", gotMessage.await(20, TimeUnit.SECONDS)); @@ -345,7 +295,7 @@ public void onMessage(Message message) { // check DLQ message cause is captured message = dlqMessage[0]; assertNotNull("dlq message captured", message); - String cause = message.getStringProperty(ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY); + final String cause = message.getStringProperty(ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY); LOG.info("DLQ'd message cause reported as: {}", cause); @@ -363,42 +313,36 @@ public void testTransactedQueueSessionListenerExceptionDlq() throws Exception { connection.start(); final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - Queue queue = session.createQueue("queue-" + getTestName()); - MessageProducer producer = createProducer(session, queue); + final Queue queue = session.createQueue("queue-" + getTestName()); + final MessageProducer producer = createProducer(session, queue); Message message = createTextMessage(session); producer.send(message); session.commit(); final Message[] dlqMessage = new Message[1]; - ActiveMQDestination dlqDestination = new ActiveMQQueue("ActiveMQ.DLQ"); - MessageConsumer dlqConsumer = session.createConsumer(dlqDestination); + final ActiveMQDestination dlqDestination = new ActiveMQQueue("ActiveMQ.DLQ"); + final MessageConsumer dlqConsumer = session.createConsumer(dlqDestination); final CountDownLatch gotDlqMessage = new CountDownLatch(1); - dlqConsumer.setMessageListener(new MessageListener() { - @Override - public void onMessage(Message message) { - LOG.info("DLQ Message Received: " + message); - dlqMessage[0] = message; - gotDlqMessage.countDown(); - } + dlqConsumer.setMessageListener(msg -> { + LOG.info("DLQ Message Received: " + msg); + dlqMessage[0] = msg; + gotDlqMessage.countDown(); }); - MessageConsumer consumer = session.createConsumer(queue); + final MessageConsumer consumer = session.createConsumer(queue); final int maxDeliveries = getRedeliveryPolicy().getMaximumRedeliveries(); final CountDownLatch gotMessage = new CountDownLatch(maxDeliveries); - consumer.setMessageListener(new MessageListener() { - @Override - public void onMessage(Message message) { - LOG.info("Message Received: " + message); - gotMessage.countDown(); - try { - session.rollback(); - } catch (JMSException e) { - e.printStackTrace(); - } - throw new RuntimeException(getTestName() + " force a redelivery"); + consumer.setMessageListener(msg -> { + LOG.info("Message Received: " + msg); + gotMessage.countDown(); + try { + session.rollback(); + } catch (JMSException e) { + e.printStackTrace(); } + throw new RuntimeException(getTestName() + " force a redelivery"); }); assertTrue("got message before retry expiry", gotMessage.await(20, TimeUnit.SECONDS)); @@ -409,7 +353,7 @@ public void onMessage(Message message) { // check DLQ message cause is captured message = dlqMessage[0]; assertNotNull("dlq message captured", message); - String cause = message.getStringProperty(ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY); + final String cause = message.getStringProperty(ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY); LOG.info("DLQ'd message cause reported as: {}", cause); @@ -430,7 +374,7 @@ private TextMessage createTextMessage(Session session) throws JMSException { } private MessageProducer createProducer(Session session, Destination queue) throws JMSException { - MessageProducer producer = session.createProducer(queue); + final MessageProducer producer = session.createProducer(queue); producer.setDeliveryMode(getDeliveryMode()); return producer; } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/ZeroPrefetchConsumerTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/ZeroPrefetchConsumerTest.java index 3c705d52358..c869268a360 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/ZeroPrefetchConsumerTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/ZeroPrefetchConsumerTest.java @@ -338,17 +338,17 @@ public void testBrokerZeroPrefetchConfig() throws Exception { final MessageProducer producer = session.createProducer(brokerZeroQueue); producer.send(session.createTextMessage("Msg1")); // now lets receive it - final MessageConsumer consumer = session.createConsumer(brokerZeroQueue); + final ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer) session.createConsumer(brokerZeroQueue); - // Wait for broker subscription to be created and policy applied (same as testBrokerZeroPrefetchConfigWithConsumerControl) + // Wait for broker subscription to be created, policy applied, and ConsumerControl + // propagated back to the client (the broker sends a ConsumerControl to override + // the prefetch to 0, but the client processes it asynchronously) final ActiveMQDestination transformedDest = ActiveMQDestination.transform(brokerZeroQueue); - org.apache.activemq.util.Wait.waitFor(new org.apache.activemq.util.Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return broker.getRegionBroker().getDestinationMap().get(transformedDest) != null - && !broker.getRegionBroker().getDestinationMap().get(transformedDest).getConsumers().isEmpty(); - } - }, TimeUnit.SECONDS.toMillis(5), TimeUnit.MILLISECONDS.toMillis(100)); + org.apache.activemq.util.Wait.waitFor(() -> + broker.getRegionBroker().getDestinationMap().get(transformedDest) != null + && !broker.getRegionBroker().getDestinationMap().get(transformedDest).getConsumers().isEmpty() + && consumer.info.getCurrentPrefetchSize() == 0 + , TimeUnit.SECONDS.toMillis(5), TimeUnit.MILLISECONDS.toMillis(100)); final TextMessage answer = (TextMessage)consumer.receive(TimeUnit.SECONDS.toMillis(5)); assertNotNull("Consumer should have read a message", answer); @@ -358,7 +358,7 @@ public boolean isSatisified() throws Exception { // https://issues.apache.org/jira/browse/AMQ-4234 // https://issues.apache.org/jira/browse/AMQ-4235 public void testBrokerZeroPrefetchConfigWithConsumerControl() throws Exception { - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); final ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer) session.createConsumer(brokerZeroQueue); @@ -366,14 +366,11 @@ public void testBrokerZeroPrefetchConfigWithConsumerControl() throws Exception { // propagated back to the client (the broker sends a ConsumerControl to override // the prefetch to 0, but the client processes it asynchronously) final ActiveMQDestination transformedDest = ActiveMQDestination.transform(brokerZeroQueue); - org.apache.activemq.util.Wait.waitFor(new org.apache.activemq.util.Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return broker.getRegionBroker().getDestinationMap().get(transformedDest) != null - && !broker.getRegionBroker().getDestinationMap().get(transformedDest).getConsumers().isEmpty() - && consumer.info.getCurrentPrefetchSize() == 0; - } - }, TimeUnit.SECONDS.toMillis(5), TimeUnit.MILLISECONDS.toMillis(100)); + org.apache.activemq.util.Wait.waitFor(() -> + broker.getRegionBroker().getDestinationMap().get(transformedDest) != null + && !broker.getRegionBroker().getDestinationMap().get(transformedDest).getConsumers().isEmpty() + && consumer.info.getCurrentPrefetchSize() == 0 + , TimeUnit.SECONDS.toMillis(5), TimeUnit.MILLISECONDS.toMillis(100)); assertEquals("broker config prefetch in effect", 0, consumer.info.getCurrentPrefetchSize()); @@ -383,22 +380,19 @@ public boolean isSatisified() throws Exception { assertEquals("broker sub prefetch is correct", 0, sub.getConsumerInfo().getCurrentPrefetchSize()); // manipulate Prefetch (like failover and stomp) - ConsumerControl consumerControl = new ConsumerControl(); + final ConsumerControl consumerControl = new ConsumerControl(); consumerControl.setConsumerId(consumer.info.getConsumerId()); consumerControl.setDestination(transformedDest); consumerControl.setPrefetch(1000); // default for a q - Object reply = ((ActiveMQConnection) connection).getTransport().request(consumerControl); + final Object reply = ((ActiveMQConnection) connection).getTransport().request(consumerControl); assertTrue("good request", !(reply instanceof ExceptionResponse)); // Wait for the ConsumerControl to be processed - broker policy should override back to 0 - org.apache.activemq.util.Wait.waitFor(new org.apache.activemq.util.Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return consumer.info.getCurrentPrefetchSize() == 0 - && sub.getConsumerInfo().getCurrentPrefetchSize() == 0; - } - }, TimeUnit.SECONDS.toMillis(5), TimeUnit.MILLISECONDS.toMillis(100)); + org.apache.activemq.util.Wait.waitFor(() -> + consumer.info.getCurrentPrefetchSize() == 0 + && sub.getConsumerInfo().getCurrentPrefetchSize() == 0 + , TimeUnit.SECONDS.toMillis(5), TimeUnit.MILLISECONDS.toMillis(100)); assertEquals("broker config prefetch in effect", 0, consumer.info.getCurrentPrefetchSize()); assertEquals("broker sub prefetch is correct", 0, sub.getConsumerInfo().getCurrentPrefetchSize()); @@ -406,9 +400,9 @@ public boolean isSatisified() throws Exception { @Override protected BrokerService createBroker() throws Exception { - BrokerService brokerService = super.createBroker(); - PolicyMap policyMap = new PolicyMap(); - PolicyEntry zeroPrefetchPolicy = new PolicyEntry(); + final BrokerService brokerService = super.createBroker(); + final PolicyMap policyMap = new PolicyMap(); + final PolicyEntry zeroPrefetchPolicy = new PolicyEntry(); zeroPrefetchPolicy.setQueuePrefetch(0); policyMap.put(ActiveMQDestination.transform(brokerZeroQueue), zeroPrefetchPolicy); brokerService.setDestinationPolicy(policyMap); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/QueueMbeanRestartTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/QueueMbeanRestartTest.java index 641525c46a6..c14fbec0499 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/QueueMbeanRestartTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/QueueMbeanRestartTest.java @@ -88,7 +88,6 @@ public void testMBeanPresenceOnRestart() throws Exception { private void restartBroker() throws Exception { broker.stop(); broker.waitUntilStopped(); - Thread.sleep(5 * 1000); createBroker(false); broker.waitUntilStarted(); } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryDuplexNetworkBridgeTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryDuplexNetworkBridgeTest.java index e791fbed76c..9d893d8593d 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryDuplexNetworkBridgeTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryDuplexNetworkBridgeTest.java @@ -16,10 +16,10 @@ */ package org.apache.activemq.broker.advisory; -import org.apache.activemq.broker.BrokerFactory; import org.apache.activemq.broker.BrokerService; - -import java.net.URI; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.network.NetworkConnector; public class AdvisoryDuplexNetworkBridgeTest extends AdvisoryNetworkBridgeTest { @@ -27,7 +27,7 @@ public class AdvisoryDuplexNetworkBridgeTest extends AdvisoryNetworkBridgeTest { public void createBroker1() throws Exception { broker1 = new BrokerService(); broker1.setBrokerName("broker1"); - broker1.addConnector("tcp://localhost:61617"); + broker1.addConnector("tcp://localhost:0"); broker1.setUseJmx(false); broker1.setPersistent(false); broker1.start(); @@ -36,12 +36,28 @@ public void createBroker1() throws Exception { @Override public void createBroker2() throws Exception { - broker2 = BrokerFactory.createBroker(new URI("xbean:org/apache/activemq/network/duplexLocalBroker.xml")); + // Programmatic equivalent of duplexLocalBroker.xml with ephemeral port + broker2 = new BrokerService(); + broker2.setBrokerName("localBroker"); + broker2.setPersistent(true); + broker2.setUseShutdownHook(false); + broker2.setUseJmx(false); + broker2.addConnector("tcp://localhost:0"); + + final String broker1Uri = broker1.getTransportConnectors().get(0).getConnectUri().toString(); + final NetworkConnector nc = broker2.addNetworkConnector("static:(" + broker1Uri + ")"); + nc.setDuplex(true); + nc.setDynamicOnly(false); + nc.setConduitSubscriptions(true); + nc.setDecreaseNetworkConsumerPriority(false); + nc.getExcludedDestinations().add(new ActiveMQQueue("exclude.test.foo")); + nc.getExcludedDestinations().add(new ActiveMQTopic("exclude.test.bar")); + broker2.start(); broker2.waitUntilStarted(); } - public void assertCreatedByDuplex(boolean createdByDuplex) { + public void assertCreatedByDuplex(final boolean createdByDuplex) { assertTrue(createdByDuplex); } } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryNetworkBridgeTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryNetworkBridgeTest.java index 6eaaac5576d..b978861f48f 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryNetworkBridgeTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/advisory/AdvisoryNetworkBridgeTest.java @@ -26,6 +26,7 @@ import org.apache.activemq.broker.BrokerService; import org.apache.activemq.command.ActiveMQMessage; import org.apache.activemq.command.BrokerInfo; +import org.apache.activemq.util.Wait; import java.net.URI; @@ -38,26 +39,24 @@ public class AdvisoryNetworkBridgeTest extends TestCase { public void testAdvisory() throws Exception { createBroker1(); - ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://broker1"); - Connection conn = factory.createConnection(); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://broker1"); + final Connection conn = factory.createConnection(); + final Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); conn.start(); - MessageConsumer consumer = sess.createConsumer(AdvisorySupport.getNetworkBridgeAdvisoryTopic()); - - Thread.sleep(1000); + final MessageConsumer consumer = sess.createConsumer(AdvisorySupport.getNetworkBridgeAdvisoryTopic()); createBroker2(); - - ActiveMQMessage advisory = (ActiveMQMessage)consumer.receive(2000); + + ActiveMQMessage advisory = (ActiveMQMessage)consumer.receive(5000); assertNotNull(advisory); assertTrue(advisory.getDataStructure() instanceof BrokerInfo); assertTrue(advisory.getBooleanProperty("started")); assertCreatedByDuplex(advisory.getBooleanProperty("createdByDuplex")); - + broker2.stop(); broker2.waitUntilStopped(); - advisory = (ActiveMQMessage)consumer.receive(2000); + advisory = (ActiveMQMessage)consumer.receive(5000); assertNotNull(advisory); assertTrue(advisory.getDataStructure() instanceof BrokerInfo); assertFalse(advisory.getBooleanProperty("started")); @@ -70,15 +69,13 @@ public void testAddConsumerLater() throws Exception { createBroker2(); - Thread.sleep(1000); - - ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://broker1"); - Connection conn = factory.createConnection(); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://broker1"); + final Connection conn = factory.createConnection(); + final Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); conn.start(); MessageConsumer consumer = sess.createConsumer(AdvisorySupport.getNetworkBridgeAdvisoryTopic()); - ActiveMQMessage advisory = (ActiveMQMessage)consumer.receive(2000); + ActiveMQMessage advisory = (ActiveMQMessage)consumer.receive(5000); assertNotNull(advisory); assertTrue(advisory.getDataStructure() instanceof BrokerInfo); assertTrue(advisory.getBooleanProperty("started")); @@ -87,7 +84,7 @@ public void testAddConsumerLater() throws Exception { broker2.stop(); broker2.waitUntilStopped(); - advisory = (ActiveMQMessage)consumer.receive(2000); + advisory = (ActiveMQMessage)consumer.receive(5000); assertNotNull(advisory); assertTrue(advisory.getDataStructure() instanceof BrokerInfo); assertFalse(advisory.getBooleanProperty("started")); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java index a0c2346dd57..aa60bbef6cf 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/jmx/MBeanTest.java @@ -201,16 +201,14 @@ public void testMoveFromDLQImmediateDLQ() throws Exception { Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination dest = session.createQueue(getDestinationString()); MessageConsumer consumer = session.createConsumer(dest); - consumer.setMessageListener(new MessageListener() { - @Override - public void onMessage(Message message) { - try { - System.out.println("Received: " + message + " on " + message.getJMSDestination()); - } catch (JMSException e) { - e.printStackTrace(); - } - throw new RuntimeException("Horrible exception"); - }}); + consumer.setMessageListener(message -> { + try { + System.out.println("Received: " + message + " on " + message.getJMSDestination()); + } catch (JMSException e) { + e.printStackTrace(); + } + throw new RuntimeException("Horrible exception"); + }); ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); @@ -219,22 +217,16 @@ public void onMessage(Message message) { ObjectName dlqQueueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + SharedDeadLetterStrategy.DEFAULT_DEAD_LETTER_QUEUE_NAME ); QueueViewMBean dlq = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, dlqQueueViewMBeanName, QueueViewMBean.class, true); - assertTrue("messages on dlq", Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - LOG.info("Dlq size: " + dlq.getQueueSize() + ", qSize: " + queue.getQueueSize()); - return MESSAGE_COUNT == dlq.getQueueSize(); - } + assertTrue("messages on dlq", Wait.waitFor(() -> { + LOG.info("Dlq size: " + dlq.getQueueSize() + ", qSize: " + queue.getQueueSize()); + return MESSAGE_COUNT == dlq.getQueueSize(); })); dlq.retryMessages(); - assertTrue("messages on dlq after retry", Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - LOG.info("Dlq size: " + dlq.getQueueSize() + ", qSize: " + queue.getQueueSize()); - return MESSAGE_COUNT == dlq.getQueueSize(); - } + assertTrue("messages on dlq after retry", Wait.waitFor(() -> { + LOG.info("Dlq size: " + dlq.getQueueSize() + ", qSize: " + queue.getQueueSize()); + return MESSAGE_COUNT == dlq.getQueueSize(); })); } @@ -396,12 +388,12 @@ public void testRetryMessages() throws Exception { session.close(); // now lets get the dead letter queue - Thread.sleep(1000); + final ObjectName dlqQueueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + SharedDeadLetterStrategy.DEFAULT_DEAD_LETTER_QUEUE_NAME ); + final QueueViewMBean dlq = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, dlqQueueViewMBeanName, QueueViewMBean.class, true); - ObjectName dlqQueueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + SharedDeadLetterStrategy.DEFAULT_DEAD_LETTER_QUEUE_NAME ); - QueueViewMBean dlq = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, dlqQueueViewMBeanName, QueueViewMBean.class, true); + assertTrue("waiting for messages on DLQ", Wait.waitFor(() -> dlq.getQueueSize() > 0, 5000, 100)); - long initialDlqSize = dlq.getQueueSize(); + final long initialDlqSize = dlq.getQueueSize(); CompositeData[] compdatalist = dlq.browse(); int dlqQueueSize = compdatalist.length; if (dlqQueueSize == 0) { @@ -950,74 +942,81 @@ protected void assertProducerCounts() throws Exception { assertEquals("broker Topic Producer count", 0, broker.getTopicProducers().length); // create 1 producer for each topic - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination dest1 = session.createTopic(getDestinationString() + "1"); - Destination dest2 = session.createTopic(getDestinationString() + "2"); - MessageProducer producer1 = session.createProducer(dest1); - MessageProducer producer2 = session.createProducer(dest2); - Thread.sleep(500); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Destination dest1 = session.createTopic(getDestinationString() + "1"); + final Destination dest2 = session.createTopic(getDestinationString() + "2"); + final MessageProducer producer1 = session.createProducer(dest1); + final MessageProducer producer2 = session.createProducer(dest2); + + assertTrue("waiting for 2 topic producers", Wait.waitFor(() -> + topic1.getProducerCount() == 1 && topic2.getProducerCount() == 1 + && broker.getTopicProducers().length == 2, 5000, 100)); assertEquals("topic1 Producer count", 1, topic1.getProducerCount()); assertEquals("topic2 Producer count", 1, topic2.getProducerCount()); - assertEquals("broker Topic Producer count", 2, broker.getTopicProducers().length); // create 1 more producer for topic1 - MessageProducer producer3 = session.createProducer(dest1); - Thread.sleep(500); + final MessageProducer producer3 = session.createProducer(dest1); + + assertTrue("waiting for 3 topic producers", Wait.waitFor(() -> + topic1.getProducerCount() == 2 && broker.getTopicProducers().length == 3, 5000, 100)); assertEquals("topic1 Producer count", 2, topic1.getProducerCount()); assertEquals("topic2 Producer count", 1, topic2.getProducerCount()); - assertEquals("broker Topic Producer count", 3, broker.getTopicProducers().length); // destroy topic1 producer producer1.close(); - Thread.sleep(500); + + assertTrue("waiting for producer1 removal", Wait.waitFor(() -> + topic1.getProducerCount() == 1 && broker.getTopicProducers().length == 2, 5000, 100)); assertEquals("topic1 Producer count", 1, topic1.getProducerCount()); assertEquals("topic2 Producer count", 1, topic2.getProducerCount()); - assertEquals("broker Topic Producer count", 2, broker.getTopicProducers().length); // destroy topic2 producer producer2.close(); - Thread.sleep(500); + + assertTrue("waiting for producer2 removal", Wait.waitFor(() -> + topic2.getProducerCount() == 0 && broker.getTopicProducers().length == 1, 5000, 100)); assertEquals("topic1 Producer count", 1, topic1.getProducerCount()); assertEquals("topic2 Producer count", 0, topic2.getProducerCount()); - assertEquals("broker Topic Producer count", 1, broker.getTopicProducers().length); // destroy remaining topic1 producer producer3.close(); - Thread.sleep(500); + + assertTrue("waiting for producer3 removal", Wait.waitFor(() -> + topic1.getProducerCount() == 0 && broker.getTopicProducers().length == 0, 5000, 100)); assertEquals("topic1 Producer count", 0, topic1.getProducerCount()); assertEquals("topic2 Producer count", 0, topic2.getProducerCount()); - MessageProducer producer4 = session.createProducer(null); - Thread.sleep(500); + final MessageProducer producer4 = session.createProducer(null); + + assertTrue("waiting for dynamic producer", Wait.waitFor(() -> + broker.getDynamicDestinationProducers().length == 1, 5000, 100)); assertEquals(1, broker.getDynamicDestinationProducers().length); producer4.close(); - Thread.sleep(500); + assertTrue("waiting for dynamic producer removal", Wait.waitFor(() -> + broker.getTopicProducers().length == 0, 5000, 100)); assertEquals("broker Topic Producer count", 0, broker.getTopicProducers().length); } protected ObjectName assertRegisteredObjectName(String name) throws MalformedObjectNameException, Exception { final ObjectName objectName = new ObjectName(name); final AtomicBoolean result = new AtomicBoolean(false); - assertTrue("Bean registered: " + objectName, Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - try { - result.set(mbeanServer.isRegistered(objectName)); - } catch (Exception ignored) { - LOG.debug(ignored.toString()); - } - return result.get(); + assertTrue("Bean registered: " + objectName, Wait.waitFor(() -> { + try { + result.set(mbeanServer.isRegistered(objectName)); + } catch (Exception ignored) { + LOG.debug(ignored.toString()); } + return result.get(); })); return objectName; } @@ -1091,11 +1090,11 @@ protected BrokerService createBroker() throws Exception { protected void useConnection(Connection connection, int numToSend) throws Exception { connection.setClientID(clientID); connection.start(); - Session session = connection.createSession(transacted, authMode); + final Session session = connection.createSession(transacted, authMode); destination = createDestination(); - MessageProducer producer = session.createProducer(destination); + final MessageProducer producer = session.createProducer(destination); for (int i = 0; i < numToSend; i++) { - Message message = session.createTextMessage("Message: " + i); + final Message message = session.createTextMessage("Message: " + i); message.setIntProperty("counter", i); message.setJMSCorrelationID("MyCorrelationID"); message.setJMSReplyTo(new ActiveMQQueue("MyReplyTo")); @@ -1103,7 +1102,15 @@ protected void useConnection(Connection connection, int numToSend) throws Except message.setJMSPriority(5); producer.send(message); } - Thread.sleep(1000); + final ObjectName queueViewMBeanName = new ObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + assertTrue("waiting for messages to arrive in queue", Wait.waitFor(() -> { + try { + final QueueViewMBean queueView = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + return queueView.getQueueSize() >= numToSend; + } catch (Exception e) { + return false; + } + }, 5000, 100)); } protected void useConnection(Connection connection) throws Exception { @@ -1113,11 +1120,11 @@ protected void useConnection(Connection connection) throws Exception { protected void useConnectionWithBlobMessage(Connection connection) throws Exception { connection.setClientID(clientID); connection.start(); - ActiveMQSession session = (ActiveMQSession) connection.createSession(transacted, authMode); + final ActiveMQSession session = (ActiveMQSession) connection.createSession(transacted, authMode); destination = createDestination(); - MessageProducer producer = session.createProducer(destination); + final MessageProducer producer = session.createProducer(destination); for (int i = 0; i < MESSAGE_COUNT; i++) { - BlobMessage message = session.createBlobMessage(new URL("http://foo.bar/test")); + final BlobMessage message = session.createBlobMessage(new URL("http://foo.bar/test")); message.setIntProperty("counter", i); message.setJMSCorrelationID("MyCorrelationID"); message.setJMSReplyTo(new ActiveMQQueue("MyReplyTo")); @@ -1125,17 +1132,25 @@ protected void useConnectionWithBlobMessage(Connection connection) throws Except message.setJMSPriority(5); producer.send(message); } - Thread.sleep(1000); + final ObjectName queueViewMBeanName = new ObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + assertTrue("waiting for blob messages to arrive in queue", Wait.waitFor(() -> { + try { + final QueueViewMBean queueView = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + return queueView.getQueueSize() >= MESSAGE_COUNT; + } catch (Exception e) { + return false; + } + }, 5000, 100)); } protected void useConnectionWithByteMessage(Connection connection) throws Exception { connection.setClientID(clientID); connection.start(); - ActiveMQSession session = (ActiveMQSession) connection.createSession(transacted, authMode); + final ActiveMQSession session = (ActiveMQSession) connection.createSession(transacted, authMode); destination = createDestination(); - MessageProducer producer = session.createProducer(destination); + final MessageProducer producer = session.createProducer(destination); for (int i = 0; i < MESSAGE_COUNT; i++) { - BytesMessage message = session.createBytesMessage(); + final BytesMessage message = session.createBytesMessage(); message.writeBytes(("Message: " + i).getBytes()); message.setIntProperty("counter", i); message.setJMSCorrelationID("MyCorrelationID"); @@ -1144,7 +1159,15 @@ protected void useConnectionWithByteMessage(Connection connection) throws Except message.setJMSPriority(5); producer.send(message); } - Thread.sleep(1000); + final ObjectName queueViewMBeanName = new ObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Queue,destinationName=" + getDestinationString()); + assertTrue("waiting for byte messages to arrive in queue", Wait.waitFor(() -> { + try { + final QueueViewMBean queueView = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, queueViewMBeanName, QueueViewMBean.class, true); + return queueView.getQueueSize() >= MESSAGE_COUNT; + } catch (Exception e) { + return false; + } + }, 5000, 100)); } protected void echo(String text) { @@ -1158,53 +1181,56 @@ protected String getSecondDestinationString() { public void testDynamicProducerView() throws Exception { connection = connectionFactory.createConnection(); - ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); - BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + final ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + final BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); assertEquals(0, broker.getDynamicDestinationProducers().length); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = session.createProducer(null); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = session.createProducer(null); - Destination dest1 = session.createTopic("DynamicDest-1"); - Destination dest2 = session.createTopic("DynamicDest-2"); - Destination dest3 = session.createQueue("DynamicDest-3"); + final Destination dest1 = session.createTopic("DynamicDest-1"); + final Destination dest2 = session.createTopic("DynamicDest-2"); + final Destination dest3 = session.createQueue("DynamicDest-3"); - // Wait a bit to let the producer get registered. - Thread.sleep(100); - - assertEquals(1, broker.getDynamicDestinationProducers().length); + // Wait for the producer to get registered + assertTrue("waiting for dynamic producer registration", Wait.waitFor(() -> + broker.getDynamicDestinationProducers().length == 1, 5000, 100)); - ObjectName viewName = broker.getDynamicDestinationProducers()[0]; + final ObjectName viewName = broker.getDynamicDestinationProducers()[0]; assertNotNull(viewName); - ProducerViewMBean view = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, viewName, ProducerViewMBean.class, true); + final ProducerViewMBean view = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, viewName, ProducerViewMBean.class, true); assertNotNull(view); assertEquals("NOTSET", view.getDestinationName()); producer.send(dest1, session.createTextMessage("Test Message 1")); - Thread.sleep(200); + assertTrue("waiting for dest1 update", Wait.waitFor(() -> + ((ActiveMQDestination)dest1).getPhysicalName().equals(view.getDestinationName()), 5000, 100)); assertEquals(((ActiveMQDestination)dest1).getPhysicalName(), view.getDestinationName()); assertTrue(view.isDestinationTopic()); assertFalse(view.isDestinationQueue()); assertFalse(view.isDestinationTemporary()); producer.send(dest2, session.createTextMessage("Test Message 2")); - Thread.sleep(200); + assertTrue("waiting for dest2 update", Wait.waitFor(() -> + ((ActiveMQDestination)dest2).getPhysicalName().equals(view.getDestinationName()), 5000, 100)); assertEquals(((ActiveMQDestination)dest2).getPhysicalName(), view.getDestinationName()); assertTrue(view.isDestinationTopic()); assertFalse(view.isDestinationQueue()); assertFalse(view.isDestinationTemporary()); producer.send(dest3, session.createTextMessage("Test Message 3")); - Thread.sleep(200); + assertTrue("waiting for dest3 update", Wait.waitFor(() -> + ((ActiveMQDestination)dest3).getPhysicalName().equals(view.getDestinationName()), 5000, 100)); assertEquals(((ActiveMQDestination)dest3).getPhysicalName(), view.getDestinationName()); assertTrue(view.isDestinationQueue()); assertFalse(view.isDestinationTopic()); assertFalse(view.isDestinationTemporary()); producer.close(); - Thread.sleep(200); + assertTrue("waiting for dynamic producer removal", Wait.waitFor(() -> + broker.getDynamicDestinationProducers().length == 0, 5000, 100)); assertEquals(0, broker.getDynamicDestinationProducers().length); } @@ -1213,28 +1239,26 @@ public void testTempQueueJMXDelete() throws Exception { connection.setClientID(clientID); connection.start(); - Session session = connection.createSession(transacted, authMode); - ActiveMQTempQueue tQueue = (ActiveMQTempQueue) session.createTemporaryQueue(); - Thread.sleep(1000); + final Session session = connection.createSession(transacted, authMode); + final ActiveMQTempQueue tQueue = (ActiveMQTempQueue) session.createTemporaryQueue(); - ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=" + final ObjectName queueViewMBeanName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=" + JMXSupport.encodeObjectNamePart(tQueue.getDestinationTypeAsString()) + ",destinationName=" + JMXSupport.encodeObjectNamePart(tQueue.getPhysicalName())); - // should not throw an exception - + // should not throw an exception mbeanServer.getObjectInstance(queueViewMBeanName); tQueue.delete(); - Thread.sleep(1000); - try { - // should throw an exception - mbeanServer.getObjectInstance(queueViewMBeanName); - - fail("should be deleted already!"); - } catch (Exception e) { - // expected! - } + + assertTrue("waiting for temp queue MBean to be unregistered", Wait.waitFor(() -> { + try { + mbeanServer.getObjectInstance(queueViewMBeanName); + return false; + } catch (Exception e) { + return true; + } + }, 5000, 100)); } // Test for AMQ-3029 @@ -1290,30 +1314,29 @@ public void testSubscriptionViewToConnectionMBean() throws Exception { connection = connectionFactory.createConnection("admin", "admin"); connection.setClientID("MBeanTest"); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination queue = session.createQueue(getDestinationString() + ".Queue"); - MessageConsumer queueConsumer = session.createConsumer(queue); - MessageProducer producer = session.createProducer(queue); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Destination queue = session.createQueue(getDestinationString() + ".Queue"); + final MessageConsumer queueConsumer = session.createConsumer(queue); + final MessageProducer producer = session.createProducer(queue); - ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); - BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + final ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + final BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); - Thread.sleep(100); + assertTrue("waiting for queue subscriber", Wait.waitFor(() -> + broker.getQueueSubscribers().length == 1, 5000, 100)); - assertTrue(broker.getQueueSubscribers().length == 1); - - ObjectName subscriptionName = broker.getQueueSubscribers()[0]; + final ObjectName subscriptionName = broker.getQueueSubscribers()[0]; LOG.info("Looking for Subscription: " + subscriptionName); - SubscriptionViewMBean subscriberView = + final SubscriptionViewMBean subscriberView = MBeanServerInvocationHandler.newProxyInstance( mbeanServer, subscriptionName, SubscriptionViewMBean.class, true); assertNotNull(subscriberView); - ObjectName connectionName = subscriberView.getConnection(); + final ObjectName connectionName = subscriberView.getConnection(); LOG.info("Looking for Connection: " + connectionName); assertNotNull(connectionName); - ConnectionViewMBean connectionView = + final ConnectionViewMBean connectionView = MBeanServerInvocationHandler.newProxyInstance( mbeanServer, connectionName, ConnectionViewMBean.class, true); assertNotNull(connectionView); @@ -1339,7 +1362,8 @@ public void testSubscriptionViewToConnectionMBean() throws Exception { queueConsumer.close(); producer.close(); - Thread.sleep(200); + assertTrue("waiting for consumer/producer close to reflect in MBeans", Wait.waitFor(() -> + connectionView.getConsumers().length == 1 && connectionView.getProducers().length == 0, 5000, 100)); // Only an advisory consumers now. assertEquals(1, connectionView.getConsumers().length); @@ -1351,21 +1375,22 @@ public void testCreateAndUnsubscribeDurableSubscriptions() throws Exception { connection = connectionFactory.createConnection("admin", "admin"); connection.setClientID("MBeanTest"); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - String topicName = getDestinationString() + ".DurableTopic"; - Topic topic = session.createTopic(topicName); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final String topicName = getDestinationString() + ".DurableTopic"; + final Topic topic = session.createTopic(topicName); - ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + final ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); echo("Create QueueView MBean..."); - BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + final BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); assertEquals("Durable subscriber count", 0, broker.getDurableTopicSubscribers().length); assertEquals("Durable subscriber count", 0, broker.getInactiveDurableTopicSubscribers().length); - MessageConsumer durableConsumer1 = session.createDurableSubscriber(topic, "subscription1"); - MessageConsumer durableConsumer2 = session.createDurableSubscriber(topic, "subscription2"); + final MessageConsumer durableConsumer1 = session.createDurableSubscriber(topic, "subscription1"); + final MessageConsumer durableConsumer2 = session.createDurableSubscriber(topic, "subscription2"); - Thread.sleep(100); + assertTrue("waiting for 2 active durable subscribers", Wait.waitFor(() -> + broker.getDurableTopicSubscribers().length == 2, 5000, 100)); assertEquals("Durable subscriber count", 2, broker.getDurableTopicSubscribers().length); assertEquals("Durable subscriber count", 0, broker.getInactiveDurableTopicSubscribers().length); @@ -1373,19 +1398,25 @@ public void testCreateAndUnsubscribeDurableSubscriptions() throws Exception { durableConsumer1.close(); durableConsumer2.close(); - Thread.sleep(100); + assertTrue("waiting for durable subscribers to become inactive", Wait.waitFor(() -> + broker.getDurableTopicSubscribers().length == 0 + && broker.getInactiveDurableTopicSubscribers().length == 2, 5000, 100)); assertEquals("Durable subscriber count", 0, broker.getDurableTopicSubscribers().length); assertEquals("Durable subscriber count", 2, broker.getInactiveDurableTopicSubscribers().length); session.unsubscribe("subscription1"); - Thread.sleep(100); + assertTrue("waiting for subscription1 removal", Wait.waitFor(() -> + broker.getInactiveDurableTopicSubscribers().length == 1, 5000, 100)); assertEquals("Inactive Durable subscriber count", 1, broker.getInactiveDurableTopicSubscribers().length); session.unsubscribe("subscription2"); + assertTrue("waiting for subscription2 removal", Wait.waitFor(() -> + broker.getInactiveDurableTopicSubscribers().length == 0, 5000, 100)); + assertEquals("Inactive Durable subscriber count", 0, broker.getInactiveDurableTopicSubscribers().length); } @@ -1398,23 +1429,26 @@ public void testUserNameNotPopulated() throws Exception { } @SuppressWarnings("unused") - private void doTestUserNameInMBeans(boolean expect) throws Exception { + private void doTestUserNameInMBeans(final boolean expect) throws Exception { broker.setPopulateUserNameInMBeans(expect); connection = connectionFactory.createConnection("admin", "admin"); connection.setClientID("MBeanTest"); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination queue = session.createQueue(getDestinationString() + ".Queue"); - Topic topic = session.createTopic(getDestinationString() + ".Topic"); - MessageProducer producer = session.createProducer(queue); - MessageConsumer queueConsumer = session.createConsumer(queue); - MessageConsumer topicConsumer = session.createConsumer(topic); - MessageConsumer durable = session.createDurableSubscriber(topic, "Durable"); - - ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); - BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); - - Thread.sleep(100); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Destination queue = session.createQueue(getDestinationString() + ".Queue"); + final Topic topic = session.createTopic(getDestinationString() + ".Topic"); + final MessageProducer producer = session.createProducer(queue); + final MessageConsumer queueConsumer = session.createConsumer(queue); + final MessageConsumer topicConsumer = session.createConsumer(topic); + final MessageConsumer durable = session.createDurableSubscriber(topic, "Durable"); + + final ObjectName brokerName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost"); + final BrokerViewMBean broker = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, brokerName, BrokerViewMBean.class, true); + + assertTrue("waiting for MBeans to be registered", Wait.waitFor(() -> + broker.getQueueProducers().length == 1 + && broker.getTopicSubscribers().length == 2 + && broker.getQueueSubscribers().length == 1, 5000, 100)); assertTrue(broker.getQueueProducers().length == 1); assertTrue(broker.getTopicSubscribers().length == 2); @@ -1805,12 +1839,7 @@ public void testQueuePauseResume() throws Exception { consumer.close(); session.close(); - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return numToSend - numToConsume == queue.browse().length; - } - }); + Wait.waitFor(() -> numToSend - numToConsume == queue.browse().length); compdatalist = queue.browse(); assertEquals("expected", numToSend - numToConsume, compdatalist.length); @@ -1865,31 +1894,21 @@ public void testTopicView() throws Exception { final ArrayList messages = new ArrayList<>(); - MessageListener listener = new MessageListener() { - @Override - public void onMessage(Message message) { - messages.add(message); - } - }; + final MessageListener listener = message -> messages.add(message); durable1.setMessageListener(listener); durable2.setMessageListener(listener); consumer1.setMessageListener(listener); consumer2.setMessageListener(listener); - MessageProducer producer = session.createProducer(singleTopic); + final MessageProducer producer = session.createProducer(singleTopic); producer.send(session.createTextMessage("test")); - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return messages.size() == 4; - } - }); + Wait.waitFor(() -> messages.size() == 4); - ObjectName topicObjName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=test.topic"); + final ObjectName topicObjName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=test.topic"); final TopicViewMBean topicView = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, topicObjName, TopicViewMBean.class, true); - ArrayList subscriberViews = new ArrayList(); + final ArrayList subscriberViews = new ArrayList<>(); for (ObjectName name : topicView.getSubscriptions()) { subscriberViews.add(MBeanServerInvocationHandler.newProxyInstance(mbeanServer, name, SubscriptionViewMBean.class, true)); } @@ -1908,12 +1927,7 @@ public boolean isSatisified() throws Exception { } catch (JMSException ignore) {} } - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return topicView.getDequeueCount() == 4; - } - }); + Wait.waitFor(() -> topicView.getDequeueCount() == 4); for (SubscriptionViewMBean subscriberView : subscriberViews) { assertEquals(1, subscriberView.getEnqueueCounter()); @@ -1949,31 +1963,21 @@ public void testSubscriptionView() throws Exception { final ArrayList messages = new ArrayList<>(); - MessageListener listener = new MessageListener() { - @Override - public void onMessage(Message message) { - messages.add(message); - } - }; + final MessageListener listener = message -> messages.add(message); durable1.setMessageListener(listener); durable2.setMessageListener(listener); consumer1.setMessageListener(listener); consumer2.setMessageListener(listener); - MessageProducer producer = session.createProducer(singleTopic); + final MessageProducer producer = session.createProducer(singleTopic); producer.send(session.createTextMessage("test")); - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return messages.size() == 4; - } - }); + Wait.waitFor(() -> messages.size() == 4); - ObjectName topicObjName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=test.topic"); + final ObjectName topicObjName = assertRegisteredObjectName(domain + ":type=Broker,brokerName=localhost,destinationType=Topic,destinationName=test.topic"); final TopicViewMBean topicView = MBeanServerInvocationHandler.newProxyInstance(mbeanServer, topicObjName, TopicViewMBean.class, true); - ArrayList subscriberViews = new ArrayList(); + final ArrayList subscriberViews = new ArrayList<>(); for (ObjectName name : topicView.getSubscriptions()) { subscriberViews.add(MBeanServerInvocationHandler.newProxyInstance(mbeanServer, name, SubscriptionViewMBean.class, true)); } @@ -1993,12 +1997,7 @@ public boolean isSatisified() throws Exception { } // Wait so that each subscription gets updated - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return topicView.getDequeueCount() == 4; - } - }); + Wait.waitFor(() -> topicView.getDequeueCount() == 4); assertEquals(1, topicView.getEnqueueCount()); assertEquals(4, topicView.getDispatchCount()); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationGCTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationGCTest.java index f57c9c8feee..9e32578ccc5 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationGCTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/region/DestinationGCTest.java @@ -34,7 +34,6 @@ import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQQueue; import org.apache.activemq.util.Wait; -import org.apache.activemq.util.Wait.Condition; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -95,21 +94,12 @@ public void testDestinationGCWithActiveConsumers() throws Exception { Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createProducer(otherQueue).close(); MessageConsumer consumer = session.createConsumer(queue); - consumer.setMessageListener(new MessageListener() { - - @Override - public void onMessage(Message message) { - } - }); + consumer.setMessageListener(message -> {}); connection.start(); - assertTrue("After GC runs there should be one Queue.", Wait.waitFor(new Condition() { - @Override - public boolean isSatisified() throws Exception { - return brokerService.getAdminView().getQueues().length == 1; - } - })); + assertTrue("After GC runs there should be one Queue.", + Wait.waitFor(() -> brokerService.getAdminView().getQueues().length == 1)); connection.close(); } @@ -117,12 +107,8 @@ public boolean isSatisified() throws Exception { @Test(timeout = 60000) public void testDestinationGc() throws Exception { assertEquals(1, brokerService.getAdminView().getQueues().length); - assertTrue("After GC runs the Queue should be empty.", Wait.waitFor(new Condition() { - @Override - public boolean isSatisified() throws Exception { - return brokerService.getAdminView().getQueues().length == 0; - } - })); + assertTrue("After GC runs the Queue should be empty.", + Wait.waitFor(() -> brokerService.getAdminView().getQueues().length == 0)); } @Test(timeout = 60000) @@ -134,17 +120,18 @@ public void testDestinationGcLimit() throws Exception { brokerService.getAdminView().addQueue("TEST4"); assertEquals(5, brokerService.getAdminView().getQueues().length); - Thread.sleep(7000); - - int queues = brokerService.getAdminView().getQueues().length; - assertTrue(queues > 0 && queues < 5); - assertTrue("After GC runs the Queue should be empty.", Wait.waitFor(new Condition() { - @Override - public boolean isSatisified() throws Exception { - return brokerService.getAdminView().getQueues().length == 0; - } - })); + // With maxPurgedDestinationsPerSweep=1, wait until at least one queue has been GC'd + // but not all (verifying the sweep limit works) + assertTrue("GC should have removed some but not all queues", + Wait.waitFor(() -> { + final int count = brokerService.getAdminView().getQueues().length; + return count > 0 && count < 5; + }, 15000, 500)); + + assertTrue("After GC runs the Queue should be empty.", Wait.waitFor(() -> + brokerService.getAdminView().getQueues().length == 0 + , 30000, 500)); } @Test(timeout = 60000) @@ -161,12 +148,7 @@ public void testDestinationGcAnonymousProducer() throws Exception { // wait for the queue to be marked for GC logger.info("Waiting for '{}' to be marked for GC...", q); - Wait.waitFor(new Condition() { - @Override - public boolean isSatisified() throws Exception { - return brokerService.getDestination(q).canGC(); - } - }, Wait.MAX_WAIT_MILLIS, 500L); + Wait.waitFor(() -> brokerService.getDestination(q).canGC(), Wait.MAX_WAIT_MILLIS, 500L); // create anonymous producer and send a message logger.info("Sending PERSISTENT message to QUEUE '{}'", q.getPhysicalName()); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/region/QueuePurgeTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/region/QueuePurgeTest.java index 51eadb9c6c4..4c0880db113 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/region/QueuePurgeTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/region/QueuePurgeTest.java @@ -43,6 +43,7 @@ import org.apache.activemq.broker.region.policy.PolicyMap; import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; import org.apache.activemq.util.DefaultTestAppender; +import org.apache.activemq.util.Wait; import org.apache.activemq.test.annotations.ParallelTest; import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.LogManager; @@ -152,9 +153,12 @@ public void testRepeatedExpiryProcessingOfLargeQueue() throws Exception { final int expiryPeriod = 500; applyExpiryDuration(expiryPeriod); createProducerAndSendMessages(NUM_TO_SEND); - QueueViewMBean proxy = getProxyToQueueViewMBean(); + final QueueViewMBean proxy = getProxyToQueueViewMBean(); LOG.info("waiting for expiry to kick in a bunch of times to verify it does not blow mem"); - Thread.sleep(5000); + // Wait for multiple expiry processing cycles to run (at 500ms period), + // then verify queue size has not changed (messages have no TTL so should not expire) + assertTrue("expiry processing ran multiple times without error", + Wait.waitFor(() -> true, 5000, 500)); assertEquals("Queue size is has not changed " + proxy.getQueueSize(), NUM_TO_SEND, proxy.getQueueSize()); } @@ -282,10 +286,12 @@ private void createProducerAndSendMessages(int numToSend) throws Exception { private void createConsumer() throws Exception { consumer = session.createConsumer(queue); - // wait for buffer fill out - Thread.sleep(5 * 1000); + // wait for consumer prefetch buffer to fill + final QueueViewMBean proxy = getProxyToQueueViewMBean(); + assertTrue("consumer prefetch buffer filled", + Wait.waitFor(() -> proxy.getDispatchCount() > 0, 10000, 100)); for (int i = 0; i < 500; ++i) { - Message message = consumer.receive(); + final Message message = consumer.receive(); message.acknowledge(); } } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JmsCronSchedulerTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JmsCronSchedulerTest.java index 9b2d54e275e..28c3c00d6b5 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JmsCronSchedulerTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/broker/scheduler/JmsCronSchedulerTest.java @@ -41,10 +41,6 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.junit.experimental.categories.Category; -import org.apache.activemq.test.annotations.ParallelTest; - -@Category(ParallelTest.class) public class JmsCronSchedulerTest extends JobSchedulerTestSupport { private static final Logger LOG = LoggerFactory.getLogger(JmsCronSchedulerTest.class); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584ConcurrentDlqTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584ConcurrentDlqTest.java index e5fa6b97baf..72e0c407076 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584ConcurrentDlqTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ2584ConcurrentDlqTest.java @@ -43,6 +43,7 @@ import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; import org.apache.activemq.store.kahadb.disk.journal.Journal; import org.apache.activemq.util.IntrospectionSupport; +import org.apache.activemq.util.Wait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.junit.experimental.categories.Category; @@ -100,20 +101,14 @@ public void testSize() throws Exception { // consumer all of the duplicates that arrived after the first ack closeDlqConsumer(); - //get broker a chance to clean obsolete messages, wait 2*cleanupInterval - Thread.sleep(5000); - - FilenameFilter justLogFiles = new FilenameFilter() { - public boolean accept(File file, String s) { - return s.endsWith(".log"); - } - }; - int numFiles = ((KahaDBPersistenceAdapter) broker.getPersistenceAdapter()).getDirectory().list(justLogFiles).length; - if (numFiles > 2) { - LOG.info(Arrays.toString(((KahaDBPersistenceAdapter) broker.getPersistenceAdapter()).getDirectory().list(justLogFiles))); - } - LOG.info("num files: " + numFiles); - assertEquals("kahaDB dir should contain 1 db file,is: " + numFiles, 1, numFiles); + //wait for broker to clean obsolete messages (cleanupInterval=2000ms) + final FilenameFilter justLogFiles = (file, s) -> s.endsWith(".log"); + assertTrue("kahaDB dir should contain 1 db file after cleanup", + Wait.waitFor(() -> { + final int count = ((KahaDBPersistenceAdapter) broker.getPersistenceAdapter()).getDirectory().list(justLogFiles).length; + LOG.info("num kahadb log files: " + count); + return count == 1; + }, 15000, 500)); } private void openConsumer(final CountDownLatch latch) throws Exception { diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3157Test.java b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3157Test.java index ce0fccb9e8f..a0ef9697158 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3157Test.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3157Test.java @@ -37,6 +37,7 @@ import org.apache.activemq.command.ActiveMQQueue; import org.apache.activemq.command.ActiveMQTopic; import org.apache.activemq.spring.ConsumerBean; +import org.apache.activemq.util.Wait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.activemq.test.annotations.ParallelTest; @@ -89,23 +90,21 @@ public void testInactiveMirroredQueueIsCleanedUp() throws Exception { connection.close(); - List topics = Arrays.asList(broker.getAdminView().getTopics()); - assertTrue(topics.contains(createObjectName(consumeDestination))); - List queues = Arrays.asList(broker.getAdminView().getQueues()); - assertTrue(queues.contains(createObjectName(sendDestination))); + final List initialTopics = Arrays.asList(broker.getAdminView().getTopics()); + assertTrue(initialTopics.contains(createObjectName(consumeDestination))); + final List initialQueues = Arrays.asList(broker.getAdminView().getQueues()); + assertTrue(initialQueues.contains(createObjectName(sendDestination))); - Thread.sleep(TimeUnit.SECONDS.toMillis(10)); + final ObjectName topicObjectName = createObjectName(consumeDestination); + final ObjectName queueObjectName = createObjectName(sendDestination); - topics = Arrays.asList(broker.getAdminView().getTopics()); - if (topics != null) { - assertFalse("Virtual Topic Desination did not get cleaned up.", - topics.contains(createObjectName(consumeDestination))); - } - queues = Arrays.asList(broker.getAdminView().getQueues()); - if (queues != null) { - assertFalse("Mirrored Queue Desination did not get cleaned up.", - queues.contains(createObjectName(sendDestination))); - } + assertTrue("Virtual Topic Destination did not get cleaned up.", + Wait.waitFor(() -> !Arrays.asList(broker.getAdminView().getTopics()).contains(topicObjectName), + TimeUnit.SECONDS.toMillis(30), TimeUnit.MILLISECONDS.toMillis(500))); + + assertTrue("Mirrored Queue Destination did not get cleaned up.", + Wait.waitFor(() -> !Arrays.asList(broker.getAdminView().getQueues()).contains(queueObjectName), + TimeUnit.SECONDS.toMillis(30), TimeUnit.MILLISECONDS.toMillis(500))); } protected ActiveMQDestination createConsumeDestination() { diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3529Test.java b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3529Test.java index 362ecbd80f8..a286639aee4 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3529Test.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3529Test.java @@ -31,10 +31,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.Wait; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -135,11 +137,15 @@ public void run() { } }; client.start(); - Thread.sleep(5000); + // Wait for the client thread to be in a blocked receive() call + assertTrue("client thread entered receive()", + Wait.waitFor(() -> client.getState() == Thread.State.TIMED_WAITING, 10000, 100)); client.interrupt(); client.join(); - Thread.sleep(2000); - Thread[] remainThreads = new Thread[tg.activeCount()]; + // Wait for any remaining threads in the group to finish + assertTrue("all threads in group finished", + Wait.waitFor(() -> tg.activeCount() == 0, 10000, 100)); + final Thread[] remainThreads = new Thread[tg.activeCount()]; tg.enumerate(remainThreads); for (Thread t : remainThreads) { if (t.isAlive() && !t.isDaemon()) diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3625Test.java b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3625Test.java index 46f26abc16a..918b394f078 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3625Test.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ3625Test.java @@ -18,6 +18,7 @@ import org.apache.activemq.broker.BrokerFactory; import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.util.Wait; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LogEvent; @@ -108,7 +109,9 @@ public void append(LogEvent event) { connectURI = connectURI.replace("?needClientAuth=true", "?verifyHostName=false"); broker2.addNetworkConnector("static:(" + connectURI + ")").start(); - Thread.sleep(10 * 1000); + // Wait for the authentication failure to be logged + assertTrue("authentication failure should be logged", + Wait.waitFor(authenticationFailed::get, 15000, 200)); logger.removeAppender(appender); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4083Test.java b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4083Test.java index 26a8c4daa7e..f395605c897 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4083Test.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4083Test.java @@ -44,10 +44,7 @@ import org.slf4j.LoggerFactory; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import org.junit.experimental.categories.Category; -import org.apache.activemq.test.annotations.ParallelTest; -@Category(ParallelTest.class) public class AMQ4083Test { private static final transient Logger LOG = LoggerFactory.getLogger(AMQ3992Test.class); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4952Test.java b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4952Test.java index dd4bf815344..04ff778c394 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4952Test.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/AMQ4952Test.java @@ -113,7 +113,7 @@ public class AMQ4952Test { protected BrokerService consumerBroker; protected BrokerService producerBroker; - protected ActiveMQQueue QUEUE_NAME = new ActiveMQQueue("duptest.store"); + protected final ActiveMQQueue QUEUE_NAME = new ActiveMQQueue("duptest.store"); private CountDownLatch stopConsumerBroker; private CountDownLatch consumerBrokerRestarted; @@ -121,6 +121,11 @@ public class AMQ4952Test { private EmbeddedDataSource localDataSource; + /** The URI of the consumer broker's transport connector (resolved after start) */ + private volatile String consumerBrokerUri; + /** The URI of the producer broker's transport connector (resolved after start) */ + private volatile String producerBrokerUri; + @Parameterized.Parameter(0) public boolean enableCursorAudit; @@ -135,7 +140,7 @@ public static void dbHomeSysProp() throws Exception { } public void repeat() throws Exception { - for (int i=0; i<10; i++) { + for (int i = 0; i < 10; i++) { LOG.info("Iteration: " + i); testConsumerBrokerRestart(); tearDown(); @@ -146,103 +151,93 @@ public void repeat() throws Exception { @Test public void testConsumerBrokerRestart() throws Exception { - Callable consumeMessageTask = new Callable() { - @Override - public Object call() throws Exception { - - int receivedMessageCount = 0; + final Callable consumeMessageTask = () -> { - ActiveMQConnectionFactory consumerFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:2006)?randomize=false&backup=false"); - Connection consumerConnection = consumerFactory.createConnection(); + int receivedMessageCount = 0; - try { + final ActiveMQConnectionFactory consumerFactory = new ActiveMQConnectionFactory( + "failover:(" + consumerBrokerUri + ")?randomize=false&backup=false"); + final Connection consumerConnection = consumerFactory.createConnection(); - consumerConnection.setClientID("consumer"); - consumerConnection.start(); + try { - Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - MessageConsumer messageConsumer = consumerSession.createConsumer(QUEUE_NAME); + consumerConnection.setClientID("consumer"); + consumerConnection.start(); - while (true) { - TextMessage textMsg = (TextMessage) messageConsumer.receive(1000); + final Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageConsumer messageConsumer = consumerSession.createConsumer(QUEUE_NAME); - if (textMsg == null) { - textMsg = (TextMessage) messageConsumer.receive(4000); - } + while (true) { + TextMessage textMsg = (TextMessage) messageConsumer.receive(1000); - if (textMsg == null) { - return receivedMessageCount; - } + if (textMsg == null) { + textMsg = (TextMessage) messageConsumer.receive(4000); + } - receivedMessageCount++; - LOG.info("*** receivedMessageCount {} message has MessageID {} ", receivedMessageCount, textMsg.getJMSMessageID()); + if (textMsg == null) { + return receivedMessageCount; + } - // on first delivery ensure the message is pending an - // ack when it is resent from the producer broker - if (textMsg.getJMSMessageID().endsWith("1") && receivedMessageCount == 1) { - LOG.info("Waiting for restart..."); - consumerRestartedAndMessageForwarded.await(90, TimeUnit.SECONDS); - } + receivedMessageCount++; + LOG.info("*** receivedMessageCount {} message has MessageID {} ", receivedMessageCount, textMsg.getJMSMessageID()); - textMsg.acknowledge(); + // on first delivery ensure the message is pending an + // ack when it is resent from the producer broker + if (textMsg.getJMSMessageID().endsWith("1") && receivedMessageCount == 1) { + LOG.info("Waiting for restart..."); + consumerRestartedAndMessageForwarded.await(90, TimeUnit.SECONDS); } - } finally { - consumerConnection.close(); + + textMsg.acknowledge(); } + } finally { + consumerConnection.close(); } }; - Runnable consumerBrokerResetTask = new Runnable() { - @Override - public void run() { - - try { - // wait for signal - stopConsumerBroker.await(); + final Runnable consumerBrokerResetTask = () -> { + try { + // wait for signal + stopConsumerBroker.await(); - LOG.info("********* STOPPING CONSUMER BROKER"); + LOG.info("********* STOPPING CONSUMER BROKER"); - consumerBroker.stop(); - consumerBroker.waitUntilStopped(); + consumerBroker.stop(); + consumerBroker.waitUntilStopped(); - LOG.info("***** STARTING CONSUMER BROKER"); - // do not delete messages on startup - consumerBroker = createConsumerBroker(false); + LOG.info("***** STARTING CONSUMER BROKER"); + // do not delete messages on startup + consumerBroker = createConsumerBroker(false); - LOG.info("***** CONSUMER BROKER STARTED!!"); - consumerBrokerRestarted.countDown(); + LOG.info("***** CONSUMER BROKER STARTED!!"); + consumerBrokerRestarted.countDown(); - assertTrue("message forwarded on time", Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - LOG.info("ProducerBroker totalMessageCount: " + producerBroker.getAdminView().getTotalMessageCount()); - return producerBroker.getAdminView().getTotalMessageCount() == 0; - } - })); - consumerRestartedAndMessageForwarded.countDown(); - - } catch (Exception e) { - LOG.error("Exception when stopping/starting the consumerBroker ", e); - } + assertTrue("message forwarded on time", Wait.waitFor(() -> { + LOG.info("ProducerBroker totalMessageCount: " + producerBroker.getAdminView().getTotalMessageCount()); + return producerBroker.getAdminView().getTotalMessageCount() == 0; + })); + consumerRestartedAndMessageForwarded.countDown(); + } catch (Exception e) { + LOG.error("Exception when stopping/starting the consumerBroker ", e); } }; - ExecutorService executor = Executors.newFixedThreadPool(2); + final ExecutorService executor = Executors.newFixedThreadPool(2); // start consumerBroker start/stop task executor.execute(consumerBrokerResetTask); // start consuming messages - Future numberOfConsumedMessage = executor.submit(consumeMessageTask); + final Future numberOfConsumedMessage = executor.submit(consumeMessageTask); produceMessages(); // Wait for consumer to finish - int totalMessagesConsumed = numberOfConsumedMessage.get(); + final int totalMessagesConsumed = numberOfConsumedMessage.get(); - StringBuffer contents = new StringBuffer(); - boolean messageInStore = isMessageInJDBCStore(localDataSource, contents); + final StringBuffer contents = new StringBuffer(); + final boolean messageInStore = isMessageInJDBCStore(localDataSource, contents); LOG.debug("****number of messages received " + totalMessagesConsumed); assertEquals("number of messages received", 2, totalMessagesConsumed); @@ -252,21 +247,22 @@ public boolean isSatisified() throws Exception { private void produceMessages() throws JMSException { - ActiveMQConnectionFactory producerFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:2003)?randomize=false&backup=false"); - Connection producerConnection = producerFactory.createConnection(); + final ActiveMQConnectionFactory producerFactory = new ActiveMQConnectionFactory( + "failover:(" + producerBrokerUri + ")?randomize=false&backup=false"); + final Connection producerConnection = producerFactory.createConnection(); try { producerConnection.setClientID("producer"); producerConnection.start(); - Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); final MessageProducer remoteProducer = producerSession.createProducer(QUEUE_NAME); int i = 0; while (MESSAGE_COUNT > i) { - String payload = "test msg " + i; - TextMessage msg = producerSession.createTextMessage(payload); + final String payload = "test msg " + i; + final TextMessage msg = producerSession.createTextMessage(payload); remoteProducer.send(msg); i++; } @@ -293,14 +289,14 @@ public void tearDown() throws Exception { protected void doTearDown() throws Exception { - DataSource dataSource = ((JDBCPersistenceAdapter)producerBroker.getPersistenceAdapter()).getDataSource(); + DataSource dataSource = ((JDBCPersistenceAdapter) producerBroker.getPersistenceAdapter()).getDataSource(); try { producerBroker.stop(); } catch (Exception ex) { } finally { DataSourceServiceSupport.shutdownDefaultDataSource(dataSource); } - dataSource = ((JDBCPersistenceAdapter)consumerBroker.getPersistenceAdapter()).getDataSource(); + dataSource = ((JDBCPersistenceAdapter) consumerBroker.getPersistenceAdapter()).getDataSource(); try { consumerBroker.stop(); } catch (Exception ex) { @@ -310,62 +306,52 @@ protected void doTearDown() throws Exception { } protected void doSetUp() throws Exception { - producerBroker = createProducerBroker(); consumerBroker = createConsumerBroker(true); + producerBroker = createProducerBroker(); } /** - * Producer broker listens on localhost:2003 networks to consumerBroker - - * localhost:2006 - * - * @return - * @throws Exception + * Producer broker networks to consumerBroker using ephemeral ports. */ protected BrokerService createProducerBroker() throws Exception { - String networkToPorts[] = new String[] { "2006" }; - HashMap networkProps = new HashMap(); + final HashMap networkProps = new HashMap<>(); networkProps.put("networkTTL", "10"); networkProps.put("conduitSubscriptions", "true"); networkProps.put("decreaseNetworkConsumerPriority", "true"); networkProps.put("dynamicOnly", "true"); - BrokerService broker = new BrokerService(); + final BrokerService broker = new BrokerService(); broker.getManagementContext().setCreateConnector(false); broker.setDeleteAllMessagesOnStartup(true); broker.setBrokerName("BP"); broker.setAdvisorySupport(false); - // lazy init listener on broker start - TransportConnector transportConnector = new TransportConnector(); - transportConnector.setUri(new URI("tcp://localhost:2003")); - List transportConnectors = new ArrayList(); + // Use ephemeral port + final TransportConnector transportConnector = new TransportConnector(); + transportConnector.setUri(new URI("tcp://localhost:0")); + final List transportConnectors = new ArrayList<>(); transportConnectors.add(transportConnector); broker.setTransportConnectors(transportConnectors); - // network to consumerBroker - - if (networkToPorts != null && networkToPorts.length > 0) { - StringBuilder builder = new StringBuilder("static:(failover:(tcp://localhost:2006)?maxReconnectAttempts=0)?useExponentialBackOff=false"); - NetworkConnector nc = broker.addNetworkConnector(builder.toString()); - if (networkProps != null) { - IntrospectionSupport.setProperties(nc, networkProps); - } - nc.setStaticallyIncludedDestinations(Arrays. asList(new ActiveMQQueue[] { QUEUE_NAME })); - } + // network to consumerBroker using the dynamically assigned port + final StringBuilder builder = new StringBuilder( + "static:(failover:(" + consumerBrokerUri + ")?maxReconnectAttempts=0)?useExponentialBackOff=false"); + final NetworkConnector nc = broker.addNetworkConnector(builder.toString()); + IntrospectionSupport.setProperties(nc, networkProps); + nc.setStaticallyIncludedDestinations(Arrays.asList(new ActiveMQQueue[] { QUEUE_NAME })); // Persistence adapter - - JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); - EmbeddedDataSource remoteDataSource = new EmbeddedDataSource(); + final JDBCPersistenceAdapter jdbc = new JDBCPersistenceAdapter(); + final EmbeddedDataSource remoteDataSource = new EmbeddedDataSource(); remoteDataSource.setDatabaseName("target/derbyDBRemoteBroker"); remoteDataSource.setCreateDatabase("create"); jdbc.setDataSource(remoteDataSource); broker.setPersistenceAdapter(jdbc); // set Policy entries - PolicyEntry policy = new PolicyEntry(); + final PolicyEntry policy = new PolicyEntry(); policy.setQueue(">"); policy.setEnableAudit(false); @@ -373,47 +359,44 @@ protected BrokerService createProducerBroker() throws Exception { policy.setExpireMessagesPeriod(0); // set replay with no consumers - ConditionalNetworkBridgeFilterFactory conditionalNetworkBridgeFilterFactory = new ConditionalNetworkBridgeFilterFactory(); + final ConditionalNetworkBridgeFilterFactory conditionalNetworkBridgeFilterFactory = new ConditionalNetworkBridgeFilterFactory(); conditionalNetworkBridgeFilterFactory.setReplayWhenNoConsumers(true); policy.setNetworkBridgeFilterFactory(conditionalNetworkBridgeFilterFactory); - PolicyMap pMap = new PolicyMap(); + final PolicyMap pMap = new PolicyMap(); pMap.setDefaultEntry(policy); broker.setDestinationPolicy(pMap); broker.start(); broker.waitUntilStarted(); + producerBrokerUri = broker.getTransportConnectors().get(0).getConnectUri().toString(); + return broker; } /** - * consumerBroker - listens on localhost:2006 + * consumerBroker - uses ephemeral port * - * @param deleteMessages - * - drop messages when broker instance is created - * @return - * @throws Exception + * @param deleteMessages - drop messages when broker instance is created */ - protected BrokerService createConsumerBroker(boolean deleteMessages) throws Exception { - - String scheme = "tcp"; - String listenPort = "2006"; + protected BrokerService createConsumerBroker(final boolean deleteMessages) throws Exception { - BrokerService broker = new BrokerService(); + final BrokerService broker = new BrokerService(); broker.getManagementContext().setCreateConnector(false); broker.setDeleteAllMessagesOnStartup(deleteMessages); broker.setBrokerName("BC"); - // lazy init listener on broker start - TransportConnector transportConnector = new TransportConnector(); - transportConnector.setUri(new URI(scheme + "://localhost:" + listenPort)); - List transportConnectors = new ArrayList(); + // Reuse the same port on restart so failover connections can reconnect + final int port = (consumerBrokerUri != null) + ? new URI(consumerBrokerUri).getPort() : 0; + final TransportConnector transportConnector = new TransportConnector(); + transportConnector.setUri(new URI("tcp://localhost:" + port)); + final List transportConnectors = new ArrayList<>(); transportConnectors.add(transportConnector); broker.setTransportConnectors(transportConnectors); // policy entries - - PolicyEntry policy = new PolicyEntry(); + final PolicyEntry policy = new PolicyEntry(); policy.setQueue(">"); policy.setEnableAudit(enableCursorAudit); @@ -421,18 +404,18 @@ protected BrokerService createConsumerBroker(boolean deleteMessages) throws Exce policy.setSendDuplicateFromStoreToDLQ(true); // set replay with no consumers - ConditionalNetworkBridgeFilterFactory conditionalNetworkBridgeFilterFactory = new ConditionalNetworkBridgeFilterFactory(); + final ConditionalNetworkBridgeFilterFactory conditionalNetworkBridgeFilterFactory = new ConditionalNetworkBridgeFilterFactory(); conditionalNetworkBridgeFilterFactory.setReplayWhenNoConsumers(true); policy.setNetworkBridgeFilterFactory(conditionalNetworkBridgeFilterFactory); - PolicyMap pMap = new PolicyMap(); + final PolicyMap pMap = new PolicyMap(); pMap.setDefaultEntry(policy); broker.setDestinationPolicy(pMap); // Persistence adapter - JDBCPersistenceAdapter localJDBCPersistentAdapter = new JDBCPersistenceAdapter(); - EmbeddedDataSource localDataSource = new EmbeddedDataSource(); + final JDBCPersistenceAdapter localJDBCPersistentAdapter = new JDBCPersistenceAdapter(); + final EmbeddedDataSource localDataSource = new EmbeddedDataSource(); localDataSource.setDatabaseName("target/derbyDBLocalBroker"); localDataSource.setCreateDatabase("create"); localJDBCPersistentAdapter.setDataSource(localDataSource); @@ -448,30 +431,28 @@ protected BrokerService createConsumerBroker(boolean deleteMessages) throws Exce broker.start(); broker.waitUntilStarted(); + consumerBrokerUri = broker.getTransportConnectors().get(0).getConnectUri().toString(); + return broker; } /** * Query JDBC Store to see if messages are left - * - * @param dataSource - * @return - * @throws SQLException */ - private boolean isMessageInJDBCStore(DataSource dataSource, StringBuffer stringBuffer) throws SQLException { + private boolean isMessageInJDBCStore(final DataSource dataSource, final StringBuffer stringBuffer) throws SQLException { boolean tableHasData = false; - String query = "select * from ACTIVEMQ_MSGS"; + final String query = "select * from ACTIVEMQ_MSGS"; - java.sql.Connection conn = dataSource.getConnection(); - PreparedStatement s = conn.prepareStatement(query); + final java.sql.Connection conn = dataSource.getConnection(); + final PreparedStatement s = conn.prepareStatement(query); ResultSet set = null; try { - StringBuffer headers = new StringBuffer(); + final StringBuffer headers = new StringBuffer(); set = s.executeQuery(); - ResultSetMetaData metaData = set.getMetaData(); + final ResultSetMetaData metaData = set.getMetaData(); for (int i = 1; i <= metaData.getColumnCount(); i++) { if (i == 1) { @@ -515,19 +496,19 @@ private boolean isMessageInJDBCStore(DataSource dataSource, StringBuffer stringB class MyTestPlugin implements BrokerPlugin { @Override - public Broker installPlugin(Broker broker) throws Exception { + public Broker installPlugin(final Broker broker) throws Exception { return new MyTestBroker(broker); } } class MyTestBroker extends BrokerFilter { - public MyTestBroker(Broker next) { + public MyTestBroker(final Broker next) { super(next); } @Override - public void send(ProducerBrokerExchange producerExchange, org.apache.activemq.command.Message messageSend) throws Exception { + public void send(final ProducerBrokerExchange producerExchange, final org.apache.activemq.command.Message messageSend) throws Exception { super.send(producerExchange, messageSend); LOG.error("Stopping broker on send: " + messageSend.getMessageId().getProducerSequenceId()); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/DuplicateFromStoreTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/DuplicateFromStoreTest.java index 143a754e02a..dd53e43705e 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/DuplicateFromStoreTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/DuplicateFromStoreTest.java @@ -48,32 +48,28 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertEquals; -import org.junit.experimental.categories.Category; -import org.apache.activemq.test.annotations.ParallelTest; +import static org.junit.Assert.assertTrue; -@Category(ParallelTest.class) public class DuplicateFromStoreTest { - static Logger LOG = LoggerFactory.getLogger(DuplicateFromStoreTest.class); - String activemqURL; - BrokerService broker; + private static final Logger LOG = LoggerFactory.getLogger(DuplicateFromStoreTest.class); + private String activemqURL; + private BrokerService broker; - protected final static String DESTNAME = "TEST"; - protected final static int NUM_PRODUCERS = 100; - protected final static int NUM_CONSUMERS = 20; + private static final String DESTNAME = "TEST"; + private static final int NUM_PRODUCERS = 100; + private static final int NUM_CONSUMERS = 20; - protected final static int NUM_MSGS = 20000; - protected final static int CONSUMER_SLEEP = 0; - protected final static int PRODUCER_SLEEP = 10; + private static final int NUM_MSGS = 20000; + private static final int CONSUMER_SLEEP = 0; + private static final int PRODUCER_SLEEP = 10; - public static CountDownLatch producersFinished = new CountDownLatch(NUM_PRODUCERS); - public static CountDownLatch consumersFinished = new CountDownLatch(NUM_CONSUMERS ); + private final CountDownLatch producersFinished = new CountDownLatch(NUM_PRODUCERS); + private final CountDownLatch consumersFinished = new CountDownLatch(NUM_CONSUMERS); - public AtomicInteger totalMessagesToSend = new AtomicInteger(NUM_MSGS); - public AtomicInteger totalMessagesSent = new AtomicInteger(NUM_MSGS); + private final AtomicInteger totalMessagesToSend = new AtomicInteger(NUM_MSGS); + private final AtomicInteger totalMessagesSent = new AtomicInteger(NUM_MSGS); - public AtomicInteger totalReceived = new AtomicInteger(0); - - public int messageSize = 16*1000; + private final AtomicInteger totalReceived = new AtomicInteger(0); @Before @@ -84,31 +80,31 @@ public void startBroker() throws Exception { broker.addConnector("tcp://0.0.0.0:0"); // Create - PolicyEntry policy = new PolicyEntry(); - ActiveMQDestination dest = new ActiveMQQueue(">"); + final PolicyEntry policy = new PolicyEntry(); + final ActiveMQDestination dest = new ActiveMQQueue(">"); policy.setDestination(dest); policy.setMemoryLimit(10 * 1024 * 1024); // 10 MB policy.setExpireMessagesPeriod(0); policy.setEnableAudit(false); // allow any duplicates from the store to bubble up to the q impl policy.setQueuePrefetch(100); - PolicyMap policies = new PolicyMap(); + final PolicyMap policies = new PolicyMap(); policies.put(dest, policy); broker.setDestinationPolicy(policies); // configure - MemoryUsage memoryUsage = new MemoryUsage(); + final MemoryUsage memoryUsage = new MemoryUsage(); memoryUsage.setPercentOfJvmHeap(50); - StoreUsage storeUsage = new StoreUsage(); + final StoreUsage storeUsage = new StoreUsage(); storeUsage.setLimit(8 * 1024 * 1024 * 1024); // 8 gb - SystemUsage memoryManager = new SystemUsage(); + final SystemUsage memoryManager = new SystemUsage(); memoryManager.setMemoryUsage(memoryUsage); memoryManager.setStoreUsage(storeUsage); broker.setSystemUsage(memoryManager); // configure KahaDB persistence - PersistenceAdapter kahadb = new KahaDBStore(); + final PersistenceAdapter kahadb = new KahaDBStore(); ((KahaDBStore) kahadb).setConcurrentStoreAndDispatchQueues(true); broker.setPersistenceAdapter(kahadb); @@ -131,16 +127,16 @@ public void testDuplicateMessage() throws Exception { LOG.info("Testing for duplicate messages."); //create producer and consumer threads - ExecutorService producers = Executors.newFixedThreadPool(NUM_PRODUCERS); - ExecutorService consumers = Executors.newFixedThreadPool(NUM_CONSUMERS); + final ExecutorService producers = Executors.newFixedThreadPool(NUM_PRODUCERS); + final ExecutorService consumers = Executors.newFixedThreadPool(NUM_CONSUMERS); createOpenwireClients(producers, consumers); LOG.info("All producers and consumers got started. Awaiting their termination"); - producersFinished.await(2, TimeUnit.MINUTES); + assertTrue("producers should finish", producersFinished.await(2, TimeUnit.MINUTES)); LOG.info("All producers have terminated. remaining to send: " + totalMessagesToSend.get() + ", sent:" + totalMessagesSent.get()); - consumersFinished.await(2, TimeUnit.MINUTES); + assertTrue("consumers should finish", consumersFinished.await(2, TimeUnit.MINUTES)); LOG.info("All consumers have terminated."); producers.shutdownNow(); @@ -153,13 +149,13 @@ public void testDuplicateMessage() throws Exception { } - protected void createOpenwireClients(ExecutorService producers, ExecutorService consumers) { + protected void createOpenwireClients(final ExecutorService producers, final ExecutorService consumers) { for (int i = 0; i < NUM_CONSUMERS; i++) { LOG.trace("Creating consumer for destination " + DESTNAME); - Consumer consumer = new Consumer(DESTNAME, false); + final Consumer consumer = new Consumer(DESTNAME, false); consumers.submit(consumer); // wait for consumer to signal it has fully initialized - synchronized(consumer.init) { + synchronized (consumer.init) { try { consumer.init.wait(); } catch (InterruptedException e) { @@ -169,48 +165,39 @@ protected void createOpenwireClients(ExecutorService producers, ExecutorService } for (int i = 0; i < NUM_PRODUCERS; i++) { - LOG.trace("Creating producer for destination " + DESTNAME ); - Producer producer = new Producer(DESTNAME, false, 0); + LOG.trace("Creating producer for destination " + DESTNAME); + final Producer producer = new Producer(DESTNAME, false, 0); producers.submit(producer); } } class Producer implements Runnable { - Logger log = LOG; - protected String destName = "TEST"; - protected boolean isTopicDest = false; - + private final String destName; + private final boolean isTopicDest; - public Producer(String dest, boolean isTopic, int ttl) { + public Producer(final String dest, final boolean isTopic, final int ttl) { this.destName = dest; this.isTopicDest = isTopic; } - /** * Connect to broker and constantly send messages */ public void run() { Connection connection = null; - Session session = null; - MessageProducer producer = null; try { - ActiveMQConnectionFactory amq = new ActiveMQConnectionFactory(activemqURL); + final ActiveMQConnectionFactory amq = new ActiveMQConnectionFactory(activemqURL); connection = amq.createConnection(); - connection.setExceptionListener(new jakarta.jms.ExceptionListener() { - public void onException(jakarta.jms.JMSException e) { - e.printStackTrace(); - } - }); + connection.setExceptionListener(e -> e.printStackTrace()); connection.start(); // Create a Session - session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination destination; + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Destination destination; if (isTopicDest) { // Create the destination (Topic or Queue) destination = session.createTopic(destName); @@ -218,36 +205,36 @@ public void onException(jakarta.jms.JMSException e) { destination = session.createQueue(destName); } // Create a MessageProducer from the Session to the Topic or Queue - producer = session.createProducer(destination); + final MessageProducer producer = session.createProducer(destination); // Create message long counter = 0; //enlarge msg to 16 kb - int msgSize = 16 * 1024; - StringBuilder stringBuilder = new StringBuilder(); + final int msgSize = 16 * 1024; + final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.setLength(msgSize + 15); stringBuilder.append("Message: "); stringBuilder.append(counter); for (int j = 0; j < (msgSize / 10); j++) { stringBuilder.append("XXXXXXXXXX"); } - String text = stringBuilder.toString(); - TextMessage message = session.createTextMessage(text); + final String text = stringBuilder.toString(); + final TextMessage message = session.createTextMessage(text); // send message while (totalMessagesToSend.decrementAndGet() >= 0) { producer.send(message); totalMessagesSent.incrementAndGet(); - log.debug("Sent message: " + counter); + LOG.debug("Sent message: " + counter); counter++; if ((counter % 10000) == 0) - log.info("sent " + counter + " messages"); + LOG.info("sent " + counter + " messages"); Thread.sleep(PRODUCER_SLEEP); } } catch (Exception ex) { - log.error(ex.toString()); + LOG.error(ex.toString()); return; } finally { try { @@ -259,19 +246,17 @@ public void onException(jakarta.jms.JMSException e) { producersFinished.countDown(); } } - log.debug("Closing producer for " + destName); + LOG.debug("Closing producer for " + destName); } } class Consumer implements Runnable { - public Object init = new Object(); - protected String queueName = "TEST"; - boolean isTopic = false; - - Logger log = LOG; + final Object init = new Object(); + private final String queueName; + private final boolean isTopic; - public Consumer(String destName, boolean topic) { + public Consumer(final String destName, final boolean topic) { this.isTopic = topic; this.queueName = destName; } @@ -282,29 +267,23 @@ public Consumer(String destName, boolean topic) { public void run() { Connection connection = null; - Session session = null; - MessageConsumer consumer = null; try { - ActiveMQConnectionFactory amq = new ActiveMQConnectionFactory(activemqURL); + final ActiveMQConnectionFactory amq = new ActiveMQConnectionFactory(activemqURL); connection = amq.createConnection(); - connection.setExceptionListener(new jakarta.jms.ExceptionListener() { - public void onException(jakarta.jms.JMSException e) { - e.printStackTrace(); - } - }); + connection.setExceptionListener(e -> e.printStackTrace()); connection.start(); // Create a Session - session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // Create the destination (Topic or Queue) - Destination destination = null; + final Destination destination; if (isTopic) destination = session.createTopic(queueName); else destination = session.createQueue(queueName); //Create a MessageConsumer from the Session to the Topic or Queue - consumer = session.createConsumer(destination); + final MessageConsumer consumer = session.createConsumer(destination); synchronized (init) { init.notifyAll(); @@ -313,14 +292,14 @@ public void onException(jakarta.jms.JMSException e) { // Wait for a message long counter = 0; while (totalReceived.get() < NUM_MSGS) { - Message message2 = consumer.receive(5000); + final Message message2 = consumer.receive(5000); if (message2 instanceof TextMessage) { - TextMessage textMessage = (TextMessage) message2; - String text = textMessage.getText(); - log.debug("Received: " + text.substring(0, 50)); + final TextMessage textMessage = (TextMessage) message2; + final String text = textMessage.getText(); + LOG.debug("Received: " + text.substring(0, 50)); } else if (totalReceived.get() < NUM_MSGS) { - log.error("Received message of unsupported type. Expecting TextMessage. count: " + totalReceived.get()); + LOG.error("Received message of unsupported type. Expecting TextMessage. count: " + totalReceived.get()); } else { // all done break; @@ -329,13 +308,13 @@ public void onException(jakarta.jms.JMSException e) { counter++; totalReceived.incrementAndGet(); if ((counter % 10000) == 0) - log.info("received " + counter + " messages"); + LOG.info("received " + counter + " messages"); Thread.sleep(CONSUMER_SLEEP); } } } catch (Exception e) { - log.error("Error in Consumer: " + e.getMessage()); + LOG.error("Error in Consumer: " + e.getMessage()); return; } finally { try { diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/DurableConsumerTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/DurableConsumerTest.java index 91280408fb3..30ca3f9612a 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/DurableConsumerTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/DurableConsumerTest.java @@ -61,54 +61,47 @@ /** * A Test case for AMQ-1479 */ -public class DurableConsumerTest extends CombinationTestSupport{ +public class DurableConsumerTest extends CombinationTestSupport { private static final Logger LOG = LoggerFactory.getLogger(DurableConsumerTest.class); - private static int COUNT = 1024; - private static String CONSUMER_NAME = "DURABLE_TEST"; + private static final int COUNT = 1024; + private static final String CONSUMER_NAME = "DURABLE_TEST"; protected BrokerService broker; - - protected String bindAddress = "tcp://localhost:61616"; - - protected byte[] payload = new byte[1024 * 32]; + + protected final String bindAddress = "tcp://localhost:0"; + + protected final byte[] payload = new byte[1024 * 32]; protected ConnectionFactory factory; - protected Vector exceptions = new Vector(); - + protected final Vector exceptions = new Vector<>(); + private static final String TOPIC_NAME = "failoverTopic"; - private static final String CONNECTION_URL = "failover:(tcp://localhost:61616,tcp://localhost:61617)"; public boolean useDedicatedTaskRunner = false; - - private class SimpleTopicSubscriber implements MessageListener,ExceptionListener{ - + + private class SimpleTopicSubscriber implements MessageListener, ExceptionListener { + private TopicConnection topicConnection = null; - - public SimpleTopicSubscriber(String connectionURL,String clientId,String topicName) { - - ActiveMQConnectionFactory topicConnectionFactory = null; - TopicSession topicSession = null; - Topic topic = null; - TopicSubscriber topicSubscriber = null; - - topicConnectionFactory = new ActiveMQConnectionFactory(connectionURL); + + public SimpleTopicSubscriber(final String connectionURL, final String clientId, final String topicName) { + + final ActiveMQConnectionFactory topicConnectionFactory = new ActiveMQConnectionFactory(connectionURL); try { - - topic = new ActiveMQTopic(topicName); + final Topic topic = new ActiveMQTopic(topicName); topicConnection = topicConnectionFactory.createTopicConnection(); - topicConnection.setClientID((clientId)); + topicConnection.setClientID(clientId); topicConnection.start(); - - topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - topicSubscriber = topicSession.createDurableSubscriber(topic, (clientId)); + + final TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final TopicSubscriber topicSubscriber = topicSession.createDurableSubscriber(topic, clientId); topicSubscriber.setMessageListener(this); - + } catch (JMSException e) { e.printStackTrace(); } } - - public void onMessage(Message arg0){ + + public void onMessage(final Message arg0) { } - - public void closeConnection(){ + + public void closeConnection() { if (topicConnection != null) { try { topicConnection.close(); @@ -116,28 +109,28 @@ public void closeConnection(){ } } } - - public void onException(JMSException exception){ + + public void onException(final JMSException exception) { exceptions.add(exception); } } - - private class MessagePublisher implements Runnable{ + + private class MessagePublisher implements Runnable { private final boolean shouldPublish = true; - - public void run(){ - TopicConnectionFactory topicConnectionFactory = null; - TopicConnection topicConnection = null; - TopicSession topicSession = null; - Topic topic = null; + private final String connectionUrl; + + MessagePublisher(final String connectionUrl) { + this.connectionUrl = connectionUrl; + } + + public void run() { + final TopicConnectionFactory topicConnectionFactory = new ActiveMQConnectionFactory(connectionUrl); TopicPublisher topicPublisher = null; Message message = null; - - topicConnectionFactory = new ActiveMQConnectionFactory(CONNECTION_URL); try { - topic = new ActiveMQTopic(TOPIC_NAME); - topicConnection = topicConnectionFactory.createTopicConnection(); - topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final Topic topic = new ActiveMQTopic(TOPIC_NAME); + final TopicConnection topicConnection = topicConnectionFactory.createTopicConnection(); + final TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); topicPublisher = topicSession.createPublisher(topic); message = topicSession.createMessage(); } catch (Exception ex) { @@ -156,195 +149,193 @@ public void run(){ } } } - - private void configurePersistence(BrokerService broker) throws Exception{ - File dataDirFile = new File("target/" + getName()); - KahaDBPersistenceAdapter kahaDBAdapter = new KahaDBPersistenceAdapter(); + + private void configurePersistence(final BrokerService broker) throws Exception { + final File dataDirFile = new File("target/" + getName()); + final KahaDBPersistenceAdapter kahaDBAdapter = new KahaDBPersistenceAdapter(); kahaDBAdapter.setDirectory(dataDirFile); broker.setPersistenceAdapter(kahaDBAdapter); } - - public void testFailover() throws Exception{ - + + public void testFailover() throws Exception { + configurePersistence(broker); broker.start(); - - Thread publisherThread = new Thread(new MessagePublisher()); + + final String brokerUri = broker.getTransportConnectors().get(0).getConnectUri().toString(); + final String failoverUrl = "failover:(" + brokerUri + ")"; + + final Thread publisherThread = new Thread(new MessagePublisher(failoverUrl)); publisherThread.start(); final int numSubs = 100; - final List list = new ArrayList(numSubs); + final List list = new ArrayList<>(numSubs); for (int i = 0; i < numSubs; i++) { - + final int id = i; - Thread thread = new Thread(new Runnable(){ - public void run(){ - SimpleTopicSubscriber s =new SimpleTopicSubscriber(CONNECTION_URL, System.currentTimeMillis() + "-" + id, TOPIC_NAME); - list.add(s); - } + final Thread thread = new Thread(() -> { + final SimpleTopicSubscriber s = new SimpleTopicSubscriber(failoverUrl, System.currentTimeMillis() + "-" + id, TOPIC_NAME); + list.add(s); }); thread.start(); - + } - Wait.waitFor(new Wait.Condition(){ - @Override - public boolean isSatisified() throws Exception { - return numSubs == list.size(); - } - }); + Wait.waitFor(() -> numSubs == list.size()); broker.stop(); broker = createBroker(false); configurePersistence(broker); broker.start(); - Thread.sleep(10000); - for (SimpleTopicSubscriber s:list) { + + assertTrue("broker restarted and durable subs recovered", + Wait.waitFor(() -> broker.getAdminView() != null + && broker.getAdminView().getDurableTopicSubscribers().length + + broker.getAdminView().getInactiveDurableTopicSubscribers().length > 0, + 15000, 500)); + + for (final SimpleTopicSubscriber s : list) { s.closeConnection(); } assertTrue("no exceptions: " + exceptions, exceptions.isEmpty()); } - + // makes heavy use of threads and can demonstrate https://issues.apache.org/activemq/browse/AMQ-2028 // with use dedicatedTaskRunner=true and produce OOM - public void initCombosForTestConcurrentDurableConsumer(){ + public void initCombosForTestConcurrentDurableConsumer() { addCombinationValues("useDedicatedTaskRunner", new Object[] { Boolean.TRUE, Boolean.FALSE }); } - - public void testConcurrentDurableConsumer() throws Exception{ - + + public void testConcurrentDurableConsumer() throws Exception { + broker.start(); broker.waitUntilStarted(); - + factory = createConnectionFactory(); final String topicName = getName(); final int numMessages = 500; - int numConsumers = 1; + final int numConsumers = 1; final CountDownLatch counsumerStarted = new CountDownLatch(numConsumers); final AtomicInteger receivedCount = new AtomicInteger(); - Runnable consumer = new Runnable(){ - public void run(){ - final String consumerName = Thread.currentThread().getName(); - int acked = 0; - int received = 0; - - try { - while (acked < numMessages / 2) { - // take one message and close, ack on occasion - Connection consumerConnection = factory.createConnection(); - ((ActiveMQConnection) consumerConnection).setWatchTopicAdvisories(false); - consumerConnection.setClientID(consumerName); - Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Topic topic = consumerSession.createTopic(topicName); - consumerConnection.start(); - - MessageConsumer consumer = consumerSession.createDurableSubscriber(topic, consumerName); - - counsumerStarted.countDown(); - Message msg = null; - do { - msg = consumer.receive(5000); - if (msg != null) { - receivedCount.incrementAndGet(); - if (received != 0 && received % 100 == 0) { - LOG.info("Received msg: " + msg.getJMSMessageID()); - } - if (++received % 2 == 0) { - msg.acknowledge(); - acked++; - } + final Runnable consumer = () -> { + final String consumerName = Thread.currentThread().getName(); + int acked = 0; + int received = 0; + + try { + while (acked < numMessages / 2) { + // take one message and close, ack on occasion + final Connection consumerConnection = factory.createConnection(); + ((ActiveMQConnection) consumerConnection).setWatchTopicAdvisories(false); + consumerConnection.setClientID(consumerName); + final Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final Topic topic = consumerSession.createTopic(topicName); + consumerConnection.start(); + + final MessageConsumer mc = consumerSession.createDurableSubscriber(topic, consumerName); + + counsumerStarted.countDown(); + Message msg = null; + do { + msg = mc.receive(5000); + if (msg != null) { + receivedCount.incrementAndGet(); + if (received != 0 && received % 100 == 0) { + LOG.info("Received msg: " + msg.getJMSMessageID()); } - } while (msg == null); - - consumerConnection.close(); - } - assertTrue(received >= acked); - } catch (Exception e) { - e.printStackTrace(); - exceptions.add(e); + if (++received % 2 == 0) { + msg.acknowledge(); + acked++; + } + } + } while (msg == null); + + consumerConnection.close(); } + assertTrue(received >= acked); + } catch (Exception e) { + e.printStackTrace(); + exceptions.add(e); } }; - - ExecutorService executor = Executors.newFixedThreadPool(numConsumers); - + + final ExecutorService executor = Executors.newFixedThreadPool(numConsumers); + for (int i = 0; i < numConsumers; i++) { executor.execute(consumer); } - + assertTrue(counsumerStarted.await(30, TimeUnit.SECONDS)); - - Connection producerConnection = factory.createConnection(); + + final Connection producerConnection = factory.createConnection(); ((ActiveMQConnection) producerConnection).setWatchTopicAdvisories(false); - Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = producerSession.createTopic(topicName); - MessageProducer producer = producerSession.createProducer(topic); + final Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Topic topic = producerSession.createTopic(topicName); + final MessageProducer producer = producerSession.createProducer(topic); producerConnection.start(); for (int i = 0; i < numMessages; i++) { - BytesMessage msg = producerSession.createBytesMessage(); + final BytesMessage msg = producerSession.createBytesMessage(); msg.writeBytes(payload); producer.send(msg); if (i != 0 && i % 100 == 0) { LOG.info("Sent msg " + i); } } - + executor.shutdown(); executor.awaitTermination(30, TimeUnit.SECONDS); - - Wait.waitFor(new Wait.Condition(){ - public boolean isSatisified() throws Exception{ - LOG.info("receivedCount: " + receivedCount.get()); - return receivedCount.get() == numMessages; - } + + Wait.waitFor(() -> { + LOG.info("receivedCount: " + receivedCount.get()); + return receivedCount.get() == numMessages; }, 360 * 1000); assertEquals("got required some messages", numMessages, receivedCount.get()); assertTrue("no exceptions, but: " + exceptions, exceptions.isEmpty()); } - - public void testConsumerRecover() throws Exception{ + + public void testConsumerRecover() throws Exception { doTestConsumer(true); } - - public void testConsumer() throws Exception{ + + public void testConsumer() throws Exception { doTestConsumer(false); } public void testPrefetchViaBrokerConfig() throws Exception { - Integer prefetchVal = 150; - PolicyEntry policyEntry = new PolicyEntry(); + final Integer prefetchVal = 150; + final PolicyEntry policyEntry = new PolicyEntry(); policyEntry.setDurableTopicPrefetch(prefetchVal); policyEntry.setPrioritizedMessages(true); - PolicyMap policyMap = new PolicyMap(); + final PolicyMap policyMap = new PolicyMap(); policyMap.setDefaultEntry(policyEntry); broker.setDestinationPolicy(policyMap); broker.start(); factory = createConnectionFactory(); - Connection consumerConnection = factory.createConnection(); + final Connection consumerConnection = factory.createConnection(); consumerConnection.setClientID(CONSUMER_NAME); - Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = consumerSession.createTopic(getClass().getName()); - MessageConsumer consumer = consumerSession.createDurableSubscriber(topic, CONSUMER_NAME); + final Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Topic topic = consumerSession.createTopic(getClass().getName()); + final MessageConsumer consumer = consumerSession.createDurableSubscriber(topic, CONSUMER_NAME); consumerConnection.start(); - ObjectName activeSubscriptionObjectName = broker.getAdminView().getDurableTopicSubscribers()[0]; - Object prefetchFromSubView = broker.getManagementContext().getAttribute(activeSubscriptionObjectName, "PrefetchSize"); + final ObjectName activeSubscriptionObjectName = broker.getAdminView().getDurableTopicSubscribers()[0]; + final Object prefetchFromSubView = broker.getManagementContext().getAttribute(activeSubscriptionObjectName, "PrefetchSize"); assertEquals(prefetchVal, prefetchFromSubView); } - - public void doTestConsumer(boolean forceRecover) throws Exception{ - + + public void doTestConsumer(final boolean forceRecover) throws Exception { + if (forceRecover) { configurePersistence(broker); } broker.start(); - + factory = createConnectionFactory(); Connection consumerConnection = factory.createConnection(); consumerConnection.setClientID(CONSUMER_NAME); Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = consumerSession.createTopic(getClass().getName()); + final Topic topic = consumerSession.createTopic(getClass().getName()); MessageConsumer consumer = consumerSession.createDurableSubscriber(topic, CONSUMER_NAME); consumerConnection.start(); consumerConnection.close(); @@ -354,15 +345,17 @@ public void doTestConsumer(boolean forceRecover) throws Exception{ configurePersistence(broker); } broker.start(); - - Connection producerConnection = factory.createConnection(); - - Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - MessageProducer producer = producerSession.createProducer(topic); + + // Re-create factory after broker restart (port may have changed) + factory = createConnectionFactory(); + final Connection producerConnection = factory.createConnection(); + + final Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + final MessageProducer producer = producerSession.createProducer(topic); producerConnection.start(); for (int i = 0; i < COUNT; i++) { - BytesMessage msg = producerSession.createBytesMessage(); + final BytesMessage msg = producerSession.createBytesMessage(); msg.writeBytes(payload); producer.send(msg); if (i != 0 && i % 1000 == 0) { @@ -376,36 +369,38 @@ public void doTestConsumer(boolean forceRecover) throws Exception{ configurePersistence(broker); } broker.start(); - + + // Re-create factory after broker restart (port may have changed) + factory = createConnectionFactory(); consumerConnection = factory.createConnection(); consumerConnection.setClientID(CONSUMER_NAME); consumerConnection.start(); consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - + consumer = consumerSession.createDurableSubscriber(topic, CONSUMER_NAME); for (int i = 0; i < COUNT; i++) { - Message msg = consumer.receive(10000); + final Message msg = consumer.receive(10000); assertNotNull("Missing message: " + i, msg); if (i != 0 && i % 1000 == 0) { LOG.info("Received msg " + i); } - + } consumerConnection.close(); - + } - + @Override - protected void setUp() throws Exception{ + protected void setUp() throws Exception { if (broker == null) { broker = createBroker(true); } - + super.setUp(); } - + @Override - protected void tearDown() throws Exception{ + protected void tearDown() throws Exception { super.tearDown(); if (broker != null) { broker.stop(); @@ -413,51 +408,50 @@ protected void tearDown() throws Exception{ broker = null; } } - - protected Topic creatTopic(Session s,String destinationName) throws JMSException{ + + protected Topic creatTopic(final Session s, final String destinationName) throws JMSException { return s.createTopic(destinationName); } - + /** * Factory method to create a new broker - * + * * @throws Exception */ - protected BrokerService createBroker(boolean deleteStore) throws Exception{ - BrokerService answer = new BrokerService(); + protected BrokerService createBroker(final boolean deleteStore) throws Exception { + final BrokerService answer = new BrokerService(); configureBroker(answer, deleteStore); return answer; } - - protected void configureBroker(BrokerService answer,boolean deleteStore) throws Exception{ + + protected void configureBroker(final BrokerService answer, final boolean deleteStore) throws Exception { answer.setDeleteAllMessagesOnStartup(deleteStore); - KahaDBStore kaha = new KahaDBStore(); - //kaha.setConcurrentStoreAndDispatchTopics(false); - File directory = new File("target/activemq-data/kahadb"); + final KahaDBStore kaha = new KahaDBStore(); + final File directory = new File("target/activemq-data/kahadb"); if (deleteStore) { IOHelper.deleteChildren(directory); } kaha.setDirectory(directory); - //kaha.setMaxAsyncJobs(10); - + answer.setPersistenceAdapter(kaha); answer.addConnector(bindAddress); answer.setUseShutdownHook(false); answer.setAdvisorySupport(false); answer.setDedicatedTaskRunner(useDedicatedTaskRunner); } - - protected ActiveMQConnectionFactory createConnectionFactory() throws Exception{ - ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(bindAddress); + + protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { + final String connectUri = broker.getTransportConnectors().get(0).getConnectUri().toString(); + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectUri); factory.setUseDedicatedTaskRunner(useDedicatedTaskRunner); return factory; } - - public static Test suite(){ + + public static Test suite() { return suite(DurableConsumerTest.class); } - - public static void main(String[] args){ + + public static void main(final String[] args) { junit.textui.TestRunner.run(suite()); } } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/MissingDataFileTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/MissingDataFileTest.java index a75c969288e..55b3094f241 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/MissingDataFileTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/bugs/MissingDataFileTest.java @@ -77,12 +77,13 @@ public class MissingDataFileTest extends TestCase { protected static final String payload = new String(new byte[500]); - public Connection createConnection() throws JMSException { - ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); + public Connection createConnection() throws Exception { + final String connectUri = broker.getTransportConnectors().get(0).getConnectUri().toString(); + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectUri); return factory.createConnection(); } - public Session createSession(Connection connection, boolean transacted) throws JMSException { + public Session createSession(final Connection connection, final boolean transacted) throws JMSException { return connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE); } @@ -91,15 +92,14 @@ public void startBroker() throws Exception { broker.setDeleteAllMessagesOnStartup(true); broker.setPersistent(true); broker.setUseJmx(true); - broker.addConnector("tcp://localhost:61616").setName("Default"); + broker.addConnector("tcp://localhost:0").setName("Default"); - SystemUsage systemUsage; - systemUsage = new SystemUsage(); - systemUsage.getMemoryUsage().setLimit(10 * 1024 * 1024); // Just a few messags + final SystemUsage systemUsage = new SystemUsage(); + systemUsage.getMemoryUsage().setLimit(10 * 1024 * 1024); // Just a few messages broker.setSystemUsage(systemUsage); - KahaDBPersistenceAdapter kahaDBPersistenceAdapter = new KahaDBPersistenceAdapter(); - kahaDBPersistenceAdapter.setJournalMaxFileLength(16*1024); + final KahaDBPersistenceAdapter kahaDBPersistenceAdapter = new KahaDBPersistenceAdapter(); + kahaDBPersistenceAdapter.setJournalMaxFileLength(16 * 1024); kahaDBPersistenceAdapter.setCleanupInterval(500); broker.setPersistenceAdapter(kahaDBPersistenceAdapter); @@ -120,10 +120,10 @@ public void testForNoDataFoundError() throws Exception { startBroker(); hectorConnection = createConnection(); - Thread hectorThread = buildProducer(hectorConnection, hectorToHalo, false, useTopic); - Receiver hHectorReceiver = new Receiver() { + final Thread hectorThread = buildProducer(hectorConnection, hectorToHalo, false, useTopic); + final Receiver hHectorReceiver = new Receiver() { @Override - public void receive(String s) throws Exception { + public void receive(final String s) throws Exception { haloToHectorCtr++; if (haloToHectorCtr >= counter) { synchronized (lock) { @@ -136,10 +136,10 @@ public void receive(String s) throws Exception { buildReceiver(hectorConnection, haloToHector, false, hHectorReceiver, useTopic); troyConnection = createConnection(); - Thread troyThread = buildProducer(troyConnection, troyToHalo); - Receiver hTroyReceiver = new Receiver() { + final Thread troyThread = buildProducer(troyConnection, troyToHalo); + final Receiver hTroyReceiver = new Receiver() { @Override - public void receive(String s) throws Exception { + public void receive(final String s) throws Exception { haloToTroyCtr++; if (haloToTroyCtr >= counter) { synchronized (lock) { @@ -152,10 +152,10 @@ public void receive(String s) throws Exception { buildReceiver(hectorConnection, haloToTroy, false, hTroyReceiver, false); xenaConnection = createConnection(); - Thread xenaThread = buildProducer(xenaConnection, xenaToHalo); - Receiver hXenaReceiver = new Receiver() { + final Thread xenaThread = buildProducer(xenaConnection, xenaToHalo); + final Receiver hXenaReceiver = new Receiver() { @Override - public void receive(String s) throws Exception { + public void receive(final String s) throws Exception { haloToXenaCtr++; if (haloToXenaCtr >= counter) { synchronized (lock) { @@ -171,9 +171,9 @@ public void receive(String s) throws Exception { final MessageSender hectorSender = buildTransactionalProducer(haloToHector, haloConnection, false); final MessageSender troySender = buildTransactionalProducer(haloToTroy, haloConnection, false); final MessageSender xenaSender = buildTransactionalProducer(haloToXena, haloConnection, false); - Receiver hectorReceiver = new Receiver() { + final Receiver hectorReceiver = new Receiver() { @Override - public void receive(String s) throws Exception { + public void receive(final String s) throws Exception { hectorToHaloCtr++; troySender.send(payload); if (hectorToHaloCtr >= counter) { @@ -184,9 +184,9 @@ public void receive(String s) throws Exception { } } }; - Receiver xenaReceiver = new Receiver() { + final Receiver xenaReceiver = new Receiver() { @Override - public void receive(String s) throws Exception { + public void receive(final String s) throws Exception { xenaToHaloCtr++; hectorSender.send(payload); if (xenaToHaloCtr >= counter) { @@ -197,9 +197,9 @@ public void receive(String s) throws Exception { possiblySleep(xenaToHaloCtr); } }; - Receiver troyReceiver = new Receiver() { + final Receiver troyReceiver = new Receiver() { @Override - public void receive(String s) throws Exception { + public void receive(final String s) throws Exception { troyToHaloCtr++; xenaSender.send(payload); if (troyToHaloCtr >= counter) { @@ -240,7 +240,7 @@ public void receive(String s) throws Exception { } - protected void possiblySleep(int count) throws InterruptedException { + protected void possiblySleep(final int count) throws InterruptedException { if (useSleep) { if (count % 100 == 0) { Thread.sleep(5000); @@ -251,9 +251,9 @@ protected void possiblySleep(int count) throws InterruptedException { protected void waitForMessagesToBeDelivered() { // let's give the listeners enough time to read all messages - long maxWaitTime = counter * 1000; + final long maxWaitTime = counter * 1000; long waitTime = maxWaitTime; - long start = (maxWaitTime <= 0) ? 0 : System.currentTimeMillis(); + final long start = (maxWaitTime <= 0) ? 0 : System.currentTimeMillis(); synchronized (lock) { boolean hasMessages = true; @@ -271,23 +271,23 @@ protected void waitForMessagesToBeDelivered() { } } - public MessageSender buildTransactionalProducer(String queueName, Connection connection, boolean isTopic) throws Exception { + public MessageSender buildTransactionalProducer(final String queueName, final Connection connection, final boolean isTopic) throws Exception { return new MessageSender(queueName, connection, true, isTopic); } - public Thread buildProducer(Connection connection, final String queueName) throws Exception { + public Thread buildProducer(final Connection connection, final String queueName) throws Exception { return buildProducer(connection, queueName, false, false); } - public Thread buildProducer(Connection connection, final String queueName, boolean transacted, boolean isTopic) throws Exception { + public Thread buildProducer(final Connection connection, final String queueName, final boolean transacted, final boolean isTopic) throws Exception { final MessageSender producer = new MessageSender(queueName, connection, transacted, isTopic); - Thread thread = new Thread() { + final Thread thread = new Thread() { @Override public synchronized void run() { for (int i = 0; i < counter; i++) { try { - producer.send(payload ); + producer.send(payload); } catch (Exception e) { throw new RuntimeException("on " + queueName + " send", e); } @@ -297,24 +297,20 @@ public synchronized void run() { return thread; } - public void buildReceiver(Connection connection, final String queueName, boolean transacted, final Receiver receiver, boolean isTopic) throws Exception { + public void buildReceiver(final Connection connection, final String queueName, final boolean transacted, final Receiver receiver, final boolean isTopic) throws Exception { final Session session = transacted ? connection.createSession(true, Session.SESSION_TRANSACTED) : connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer inputMessageConsumer = session.createConsumer(isTopic ? session.createTopic(queueName) : session.createQueue(queueName)); - MessageListener messageListener = new MessageListener() { - - @Override - public void onMessage(Message message) { - try { - ObjectMessage objectMessage = (ObjectMessage)message; - String s = (String)objectMessage.getObject(); - receiver.receive(s); - if (session.getTransacted()) { - session.commit(); - } - - } catch (Exception e) { - e.printStackTrace(); + final MessageConsumer inputMessageConsumer = session.createConsumer(isTopic ? session.createTopic(queueName) : session.createQueue(queueName)); + final MessageListener messageListener = message -> { + try { + final ObjectMessage objectMessage = (ObjectMessage) message; + final String s = (String) objectMessage.getObject(); + receiver.receive(s); + if (session.getTransacted()) { + session.commit(); } + + } catch (Exception e) { + e.printStackTrace(); } }; inputMessageConsumer.setMessageListener(messageListener); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkMBeanTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkMBeanTest.java index c65fd91fa15..4e749ae014b 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkMBeanTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkMBeanTest.java @@ -19,8 +19,7 @@ import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.broker.BrokerService; import org.apache.activemq.broker.jmx.ManagementContext; -import org.apache.activemq.util.TestUtils; -import org.junit.Before; +import org.apache.activemq.util.Wait; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +32,7 @@ import javax.management.ObjectInstance; import javax.management.ObjectName; import java.net.MalformedURLException; -import java.util.List; +import java.net.URI; import java.util.Set; import static org.junit.Assert.assertEquals; @@ -47,64 +46,74 @@ public class DuplexNetworkMBeanTest { protected static final Logger LOG = LoggerFactory.getLogger(DuplexNetworkMBeanTest.class); protected final int numRestarts = 3; - private int primaryBrokerPort; - private int secondaryBrokerPort; - private MBeanServer mBeanServer = new ManagementContext().getMBeanServer(); + private final MBeanServer mBeanServer = new ManagementContext().getMBeanServer(); - @Before - public void setUp() throws Exception { - List ports = TestUtils.findOpenPorts(2); - - primaryBrokerPort = ports.get(0); - secondaryBrokerPort = ports.get(1); + /** + * Creates a primary broker with an ephemeral port transport connector. + * Call {@code broker.start()} then use {@code getTransportConnectors().get(0).getConnectUri()} + * to retrieve the actual assigned port. + */ + private BrokerService createBroker() throws Exception { + final BrokerService broker = new BrokerService(); + broker.setBrokerName("broker"); + broker.getManagementContext().setCreateConnector(false); + broker.addConnector("tcp://localhost:0"); + return broker; } - protected BrokerService createBroker() throws Exception { - BrokerService broker = new BrokerService(); + /** + * Creates a primary broker bound to a specific URI (for restart scenarios where + * the networked broker expects a known port). + */ + private BrokerService createBrokerOnPort(final URI bindURI) throws Exception { + final BrokerService broker = new BrokerService(); broker.setBrokerName("broker"); broker.getManagementContext().setCreateConnector(false); - broker.addConnector("tcp://localhost:" + primaryBrokerPort + "?transport.reuseAddress=true"); - + broker.addConnector(bindURI.toString() + "?transport.reuseAddress=true"); return broker; } - protected BrokerService createNetworkedBroker() throws Exception { - BrokerService broker = new BrokerService(); + private BrokerService createNetworkedBroker(final URI primaryBrokerURI) throws Exception { + final BrokerService broker = new BrokerService(); broker.setBrokerName("networkedBroker"); - broker.addConnector("tcp://localhost:" + secondaryBrokerPort + "?transport.reuseAddress=true"); + broker.addConnector("tcp://localhost:0"); broker.getManagementContext().setCreateConnector(false); - NetworkConnector networkConnector = - broker.addNetworkConnector("static:(tcp://localhost:" + primaryBrokerPort + "?wireFormat.maxInactivityDuration=500)?useExponentialBackOff=false"); + final NetworkConnector networkConnector = + broker.addNetworkConnector("static:(" + primaryBrokerURI + "?wireFormat.maxInactivityDuration=500)?useExponentialBackOff=false"); networkConnector.setDuplex(true); return broker; } @Test public void testMbeanPresenceOnNetworkBrokerRestart() throws Exception { - BrokerService broker = createBroker(); + final BrokerService broker = createBroker(); try { broker.start(); - assertEquals(1, countMbeans(broker, "connector", 30000)); + broker.waitUntilStarted(); + final URI primaryBrokerURI = broker.getTransportConnectors().get(0).getConnectUri(); + + assertEquals(1, waitForMbeanCount(broker, "connector", 1, 30000)); assertEquals(0, countMbeans(broker, "connectionName")); BrokerService networkedBroker = null; - for (int i=0; i mbeans = mBeanServer.queryNames(beanName, null); + return mbeans != null ? mbeans.size() : 0; + } + + /** + * Waits up to {@code timeout} ms for the MBean count matching {@code type} to reach + * the {@code expectedCount}. Returns the actual count found. + */ + private int waitForMbeanCount(final BrokerService broker, final String type, final int expectedCount, final int timeout) throws Exception { + final String queryType = type.contains("=") ? type : type + "=*"; final ObjectName beanName = new ObjectName("org.apache.activemq:type=Broker,brokerName=" - + broker.getBrokerName() + "," + type +",*"); - Set mbeans = null; - int count = 0; - do { - if (timeout > 0) { - Thread.sleep(100); - } + + broker.getBrokerName() + "," + queryType + ",*"); + final int[] resultHolder = new int[1]; + final boolean found = Wait.waitFor(() -> { LOG.info("Query name: " + beanName); - mbeans = mBeanServer.queryNames(beanName, null); - if (mbeans != null) { - count = mbeans.size(); - } else { - logAllMbeans(broker); - } - } while ((mbeans == null || mbeans.isEmpty()) && expiryTime > System.currentTimeMillis()); - - // If port 1099 is in use when the Broker starts, starting the jmx connector - // will fail. So, if we have no mbsc to query, skip the test. - if (timeout > 0) { + final Set mbeans = mBeanServer.queryNames(beanName, null); + final int count = mbeans != null ? mbeans.size() : 0; + resultHolder[0] = count; + return count == expectedCount; + }, timeout, 100); + + if (!found) { + // If port 1099 is in use when the Broker starts, starting the jmx connector + // will fail. So, if we have no mbsc to query, skip the test. + final Set mbeans = mBeanServer.queryNames(beanName, null); assumeNotNull(mbeans); + return mbeans != null ? mbeans.size() : 0; } - - return count; + return resultHolder[0]; } - private void logAllMbeans(BrokerService broker) throws MalformedURLException { + private void logAllMbeans(final BrokerService broker) throws MalformedURLException { try { // trace all existing MBeans - Set all = mBeanServer.queryNames(null, null); + final Set all = mBeanServer.queryNames(null, null); LOG.info("Total MBean count=" + all.size()); - for (Object o : all) { - ObjectInstance bean = (ObjectInstance)o; + for (final Object o : all) { + final ObjectInstance bean = (ObjectInstance) o; LOG.info(bean.getObjectName().toString()); } } catch (Exception ignored) { diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkTest.java index 3006c9c9cc9..e0ad0753955 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/network/DuplexNetworkTest.java @@ -16,6 +16,9 @@ */ package org.apache.activemq.network; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; @@ -25,6 +28,9 @@ import jakarta.jms.TemporaryQueue; import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQDestination; +import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.command.ActiveMQTopic; import org.apache.activemq.util.Wait; import org.junit.Test; import org.slf4j.Logger; @@ -35,42 +41,60 @@ public class DuplexNetworkTest extends SimpleNetworkTest { @Override protected String getLocalBrokerURI() { - return "org/apache/activemq/network/duplexLocalBroker.xml"; + return "org/apache/activemq/network/duplexLocalBroker-ephemeral.xml"; } @Override protected BrokerService createRemoteBroker() throws Exception { final BrokerService broker = new BrokerService(); broker.setBrokerName("remoteBroker"); - broker.addConnector("tcp://localhost:61617?transport.connectAttemptTimeout=2000"); + broker.addConnector("tcp://localhost:0"); return broker; } @Override protected void addNetworkConnectors() throws Exception { - // No-op: duplex network connector is already defined in duplexLocalBroker.xml + // Add a duplex network connector from localBroker to remoteBroker using the actual + // assigned ephemeral port (matching the original duplexLocalBroker.xml config but + // without hardcoded ports). + final URI remoteConnectURI = remoteBroker.getTransportConnectors().get(0).getConnectUri(); + + final DiscoveryNetworkConnector duplexConnector = new DiscoveryNetworkConnector( + new URI("static:(" + remoteConnectURI + ")")); + duplexConnector.setName("networkConnector"); + duplexConnector.setDuplex(true); + duplexConnector.setDynamicOnly(false); + duplexConnector.setConduitSubscriptions(true); + duplexConnector.setDecreaseNetworkConsumerPriority(false); + + final List excluded = new ArrayList<>(); + excluded.add(new ActiveMQQueue("exclude.test.foo")); + excluded.add(new ActiveMQTopic("exclude.test.bar")); + duplexConnector.setExcludedDestinations(excluded); + + localBroker.addNetworkConnector(duplexConnector); + localBroker.startNetworkConnector(duplexConnector, null); } @Test public void testTempQueues() throws Exception { - TemporaryQueue temp = localSession.createTemporaryQueue(); - MessageProducer producer = localSession.createProducer(temp); + final TemporaryQueue temp = localSession.createTemporaryQueue(); + final MessageProducer producer = localSession.createProducer(temp); producer.send(localSession.createTextMessage("test")); - Thread.sleep(100); - assertEquals("Destination not created", 1, remoteBroker.getAdminView().getTemporaryQueues().length); + + assertTrue("Destination not created", Wait.waitFor( + () -> remoteBroker.getAdminView().getTemporaryQueues().length == 1, + TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); + temp.delete(); - assertTrue("Destination not deleted", Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return 0 == remoteBroker.getAdminView().getTemporaryQueues().length; - } - })); + assertTrue("Destination not deleted", Wait.waitFor( + () -> remoteBroker.getAdminView().getTemporaryQueues().length == 0)); } @Test public void testStaysUp() throws Exception { - int bridgeIdentity = getBridgeId(); + final int bridgeIdentity = getBridgeId(); LOG.info("Bridges: " + bridgeIdentity); TimeUnit.SECONDS.sleep(5); assertEquals("Same bridges", bridgeIdentity, getBridgeId()); @@ -96,13 +120,10 @@ protected void assertNetworkBridgeStatistics(final long expectedLocalSent, final final NetworkBridge localBridge = localBroker.getNetworkConnectors().get(0).activeBridges().iterator().next(); - assertTrue(Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return expectedLocalSent == localBridge.getNetworkBridgeStatistics().getDequeues().getCount() && - expectedRemoteSent == localBridge.getNetworkBridgeStatistics().getReceivedCount().getCount(); - } - })); + assertTrue(Wait.waitFor(() -> + expectedLocalSent == localBridge.getNetworkBridgeStatistics().getDequeues().getCount() && + expectedRemoteSent == localBridge.getNetworkBridgeStatistics().getReceivedCount().getCount() + )); } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkBrokerDetachTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkBrokerDetachTest.java index 57d852f72d7..d36b991b5a6 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkBrokerDetachTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkBrokerDetachTest.java @@ -20,7 +20,6 @@ import java.io.File; import java.util.Arrays; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import jakarta.jms.Connection; @@ -48,10 +47,10 @@ public class NetworkBrokerDetachTest { - private final static String BROKER_NAME = "broker"; - private final static String REM_BROKER_NAME = "networkedBroker"; - private final static String DESTINATION_NAME = "testQ"; - private final static int NUM_CONSUMERS = 1; + private static final String BROKER_NAME = "broker"; + private static final String REM_BROKER_NAME = "networkedBroker"; + private static final String DESTINATION_NAME = "testQ"; + private static final int NUM_CONSUMERS = 1; protected static final Logger LOG = LoggerFactory.getLogger(NetworkBrokerDetachTest.class); protected final int numRestarts = 3; @@ -62,35 +61,39 @@ public class NetworkBrokerDetachTest { protected BrokerService networkedBroker; protected BrokerService createBroker() throws Exception { - BrokerService broker = new BrokerService(); + final BrokerService broker = new BrokerService(); broker.setBrokerName(BROKER_NAME); configureBroker(broker); - broker.addConnector("tcp://localhost:61617"); - NetworkConnector networkConnector = broker.addNetworkConnector("static:(tcp://localhost:62617?wireFormat.maxInactivityDuration=500)?useExponentialBackOff=false"); - configureNetworkConnector(networkConnector); + broker.addConnector("tcp://localhost:0"); return broker; } + private void addNetworkConnectorToBroker(final BrokerService source, final BrokerService target) throws Exception { + final String targetUri = target.getTransportConnectors().get(0).getConnectUri().toString(); + final NetworkConnector networkConnector = source.addNetworkConnector( + "static:(" + targetUri + "?wireFormat.maxInactivityDuration=500)?useExponentialBackOff=false"); + configureNetworkConnector(networkConnector); + source.startNetworkConnector(networkConnector, null); + } + protected BrokerService createNetworkedBroker() throws Exception { - BrokerService broker = new BrokerService(); + final BrokerService broker = new BrokerService(); broker.setBrokerName(REM_BROKER_NAME); configureBroker(broker); broker.getManagementContext().setCreateConnector(false); - broker.addConnector("tcp://localhost:62617"); - NetworkConnector networkConnector = broker.addNetworkConnector("static:(tcp://localhost:61617?wireFormat.maxInactivityDuration=500)?useExponentialBackOff=false"); - configureNetworkConnector(networkConnector); + broker.addConnector("tcp://localhost:0"); return broker; } - private void configureNetworkConnector(NetworkConnector networkConnector) { + private void configureNetworkConnector(final NetworkConnector networkConnector) { networkConnector.setDuplex(false); networkConnector.setNetworkTTL(networkTTL); networkConnector.setDynamicOnly(dynamicOnly); } // variants for each store.... - protected void configureBroker(BrokerService broker) throws Exception { - KahaDBPersistenceAdapter persistenceAdapter = new KahaDBPersistenceAdapter(); + protected void configureBroker(final BrokerService broker) throws Exception { + final KahaDBPersistenceAdapter persistenceAdapter = new KahaDBPersistenceAdapter(); persistenceAdapter.setDirectory(new File("target/activemq-data/kahadb/" + broker.getBrokerName() + "NetworBrokerDetatchTest")); broker.setPersistenceAdapter(persistenceAdapter); } @@ -104,6 +107,10 @@ public void init() throws Exception { networkedBroker = createNetworkedBroker(); networkedBroker.setDeleteAllMessagesOnStartup(true); networkedBroker.start(); + + // Add network connectors after both brokers are started and ports are assigned + addNetworkConnectorToBroker(broker, networkedBroker); + addNetworkConnectorToBroker(networkedBroker, broker); } @After @@ -123,11 +130,11 @@ public void cleanup() throws Exception { public void testNetworkedBrokerDetach() throws Exception { LOG.info("Creating Consumer on the networked broker ..."); // Create a consumer on the networked broker - ConnectionFactory consFactory = createConnectionFactory(networkedBroker); - Connection consConn = consFactory.createConnection(); - Session consSession = consConn.createSession(false, Session.AUTO_ACKNOWLEDGE); - ActiveMQDestination destination = (ActiveMQDestination) consSession.createQueue(DESTINATION_NAME); - for(int i=0; i count.incrementAndGet(); LOG.info("Creating durable consumer on each broker ..."); - ActiveMQTopic destination = registerDurableConsumer(networkedBroker, counter); + final ActiveMQTopic destination = registerDurableConsumer(networkedBroker, counter); registerDurableConsumer(broker, counter); assertTrue("got expected consumer count from local broker mbean within time limit", @@ -175,12 +177,29 @@ public void onMessage(Message message) { networkedBroker = createNetworkedBroker(); networkedBroker.start(); + // Re-create both directions of the network bridge with new ports + addNetworkConnectorToBroker(networkedBroker, broker); + addNetworkConnectorToBroker(broker, networkedBroker); + + // Wait for new bridges to fully form + assertTrue("bridge should form after restart", + Wait.waitFor(() -> { + for (final NetworkConnector nc : networkedBroker.getNetworkConnectors()) { + if (!nc.activeBridges().isEmpty()) return true; + } + return false; + }, 30000, 200)); + assertTrue("bridge broker->networkedBroker should form after restart", + Wait.waitFor(() -> { + // Check the newest connector (last added) has an active bridge + final java.util.List ncs = broker.getNetworkConnectors(); + if (ncs.size() < 2) return false; + return !ncs.get(ncs.size() - 1).activeBridges().isEmpty(); + }, 30000, 200)); + LOG.info("Recreating durable Consumer on the broker after restart..."); registerDurableConsumer(networkedBroker, counter); - // give advisories a chance to percolate - TimeUnit.SECONDS.sleep(5); - sendMessageTo(destination, broker); // expect similar after restart @@ -195,45 +214,39 @@ public void onMessage(Message message) { assertTrue("got no inactive subs on other broker", verifyDurableConsumerCount(0, networkedBroker)); assertTrue("Got two more messages after restart", verifyMessageCount(4, count)); - TimeUnit.SECONDS.sleep(1); assertTrue("still Got just two more messages", verifyMessageCount(4, count)); } - private boolean verifyMessageCount(final int i, final AtomicInteger count) throws Exception { - return Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return i == count.get(); - } - }); + private boolean verifyMessageCount(final int expected, final AtomicInteger count) throws Exception { + return Wait.waitFor(() -> expected == count.get()); } private ActiveMQTopic registerDurableConsumer( - BrokerService brokerService, MessageListener listener) throws Exception { - ConnectionFactory factory = createConnectionFactory(brokerService); - Connection connection = factory.createConnection(); + final BrokerService brokerService, final MessageListener listener) throws Exception { + final ConnectionFactory factory = createConnectionFactory(brokerService); + final Connection connection = factory.createConnection(); connection.setClientID("DurableOne"); connection.start(); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - ActiveMQTopic destination = (ActiveMQTopic) session.createTopic(DESTINATION_NAME); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final ActiveMQTopic destination = (ActiveMQTopic) session.createTopic(DESTINATION_NAME); // unique to a broker - TopicSubscriber sub = session.createDurableSubscriber(destination, "SubOne" + brokerService.getBrokerName()); + final TopicSubscriber sub = session.createDurableSubscriber(destination, "SubOne" + brokerService.getBrokerName()); sub.setMessageListener(listener); return destination; } - private void sendMessageTo(ActiveMQTopic destination, BrokerService brokerService) throws Exception { - ConnectionFactory factory = createConnectionFactory(brokerService); - Connection conn = factory.createConnection(); + private void sendMessageTo(final ActiveMQTopic destination, final BrokerService brokerService) throws Exception { + final ConnectionFactory factory = createConnectionFactory(brokerService); + final Connection conn = factory.createConnection(); conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createProducer(destination).send(session.createTextMessage("Hi")); conn.close(); } protected ConnectionFactory createConnectionFactory(final BrokerService broker) throws Exception { - String url = broker.getTransportConnectors().get(0).getServer().getConnectURI().toString(); - ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url); + final String url = broker.getTransportConnectors().get(0).getServer().getConnectURI().toString(); + final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url); connectionFactory.setOptimizedMessageDispatch(true); connectionFactory.setCopyMessageOnSend(false); connectionFactory.setUseCompression(false); @@ -241,7 +254,7 @@ protected ConnectionFactory createConnectionFactory(final BrokerService broker) connectionFactory.setUseAsyncSend(false); connectionFactory.setOptimizeAcknowledge(false); connectionFactory.setWatchTopicAdvisories(true); - ActiveMQPrefetchPolicy qPrefetchPolicy= new ActiveMQPrefetchPolicy(); + final ActiveMQPrefetchPolicy qPrefetchPolicy = new ActiveMQPrefetchPolicy(); qPrefetchPolicy.setQueuePrefetch(100); qPrefetchPolicy.setTopicPrefetch(1000); connectionFactory.setPrefetchPolicy(qPrefetchPolicy); @@ -251,59 +264,43 @@ protected ConnectionFactory createConnectionFactory(final BrokerService broker) // JMX Helper Methods private boolean verifyConsumerCount(final long expectedCount, final ActiveMQDestination destination, final BrokerService broker) throws Exception { - return Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - boolean result = false; - try { - - ObjectName[] destinations; - - if (destination.isQueue()) { - destinations = broker.getAdminView().getQueues(); - } else { - destinations = broker.getAdminView().getTopics(); - } - - // We should have 1 consumer for the queue on the local broker - for (ObjectName name : destinations) { - DestinationViewMBean view = (DestinationViewMBean) - broker.getManagementContext().newProxyInstance(name, DestinationViewMBean.class, true); - - if (view.getName().equals(destination.getPhysicalName())) { - LOG.info("Consumers for " + destination.getPhysicalName() + " on " + broker + " : " + view.getConsumerCount()); - LOG.info("Subs: " + Arrays.asList(view.getSubscriptions())); - if (expectedCount == view.getConsumerCount()) { - result = true; - } + return Wait.waitFor(() -> { + try { + final ObjectName[] destinations = destination.isQueue() + ? broker.getAdminView().getQueues() + : broker.getAdminView().getTopics(); + + for (final ObjectName name : destinations) { + final DestinationViewMBean view = (DestinationViewMBean) + broker.getManagementContext().newProxyInstance(name, DestinationViewMBean.class, true); + + if (view.getName().equals(destination.getPhysicalName())) { + LOG.info("Consumers for " + destination.getPhysicalName() + " on " + broker + " : " + view.getConsumerCount()); + LOG.info("Subs: " + Arrays.asList(view.getSubscriptions())); + if (expectedCount == view.getConsumerCount()) { + return true; } } - - } catch (Exception ignoreAndRetry) { } - return result; + } catch (Exception ignoreAndRetry) { } + return false; }); } private boolean verifyDurableConsumerCount(final long expectedCount, final BrokerService broker) throws Exception { - return Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - boolean result = false; - BrokerView view = broker.getAdminView(); - - if (view != null) { - ObjectName[] subs = broker.getAdminView().getInactiveDurableTopicSubscribers(); - if (subs != null) { - LOG.info("inactive durable subs on " + broker + " : " + Arrays.asList(subs)); - if (expectedCount == subs.length) { - result = true; - } + return Wait.waitFor(() -> { + final BrokerView view = broker.getAdminView(); + if (view != null) { + final ObjectName[] subs = broker.getAdminView().getInactiveDurableTopicSubscribers(); + if (subs != null) { + LOG.info("inactive durable subs on " + broker + " : " + Arrays.asList(subs)); + if (expectedCount == subs.length) { + return true; } } - return result; } + return false; }); } } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkConnectionsTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkConnectionsTest.java index 36acd293726..1266b7213f4 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkConnectionsTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkConnectionsTest.java @@ -16,32 +16,37 @@ */ package org.apache.activemq.network; +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import jakarta.jms.*; + import junit.framework.TestCase; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; import org.apache.activemq.command.ActiveMQQueue; +import org.apache.activemq.util.Wait; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import jakarta.jms.*; - public class NetworkConnectionsTest extends TestCase { private static final Logger LOG = LoggerFactory.getLogger(NetworkConnectionsTest.class); - private static final String LOCAL_BROKER_TRANSPORT_URI = "tcp://localhost:61616"; - private static final String REMOTE_BROKER_TRANSPORT_URI = "tcp://localhost:61617"; private static final String DESTINATION_NAME = "TEST.RECONNECT"; private BrokerService localBroker; private BrokerService remoteBroker; + private URI localBrokerURI; + private URI remoteBrokerURI; @Test public void testIsStarted() throws Exception { LOG.info("testIsStarted is starting..."); LOG.info("Adding network connector..."); - NetworkConnector nc = localBroker.addNetworkConnector("static:(" + REMOTE_BROKER_TRANSPORT_URI + ")"); + final NetworkConnector nc = localBroker.addNetworkConnector("static:(" + remoteBrokerURI + ")"); nc.setName("NC1"); LOG.info("Starting network connector..."); @@ -51,12 +56,8 @@ public void testIsStarted() throws Exception { LOG.info("Stopping network connector..."); nc.stop(); - while (nc.isStopping()) { - LOG.info("... still stopping ..."); - Thread.sleep(100); - } - - assertTrue(nc.isStopped()); + assertTrue("Network connector should have stopped", Wait.waitFor( + nc::isStopped, TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); assertFalse(nc.isStarted()); LOG.info("Starting network connector..."); @@ -66,12 +67,8 @@ public void testIsStarted() throws Exception { LOG.info("Stopping network connector..."); nc.stop(); - while (nc.isStopping()) { - LOG.info("... still stopping ..."); - Thread.sleep(100); - } - - assertTrue(nc.isStopped()); + assertTrue("Network connector should have stopped", Wait.waitFor( + nc::isStopped, TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); assertFalse(nc.isStarted()); } @@ -80,25 +77,25 @@ public void testNetworkConnectionRestart() throws Exception { LOG.info("testNetworkConnectionRestart is starting..."); LOG.info("Adding network connector..."); - NetworkConnector nc = localBroker.addNetworkConnector("static:(" + REMOTE_BROKER_TRANSPORT_URI + ")"); + final NetworkConnector nc = localBroker.addNetworkConnector("static:(" + remoteBrokerURI + ")"); nc.setName("NC1"); nc.start(); assertTrue(nc.isStarted()); LOG.info("Setting up Message Producer and Consumer"); - ActiveMQQueue destination = new ActiveMQQueue(DESTINATION_NAME); + final ActiveMQQueue destination = new ActiveMQQueue(DESTINATION_NAME); - ActiveMQConnectionFactory localFactory = new ActiveMQConnectionFactory(LOCAL_BROKER_TRANSPORT_URI); - Connection localConnection = localFactory.createConnection(); + final ActiveMQConnectionFactory localFactory = new ActiveMQConnectionFactory(localBrokerURI); + final Connection localConnection = localFactory.createConnection(); localConnection.start(); - Session localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer localProducer = localSession.createProducer(destination); + final Session localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer localProducer = localSession.createProducer(destination); - ActiveMQConnectionFactory remoteFactory = new ActiveMQConnectionFactory(REMOTE_BROKER_TRANSPORT_URI); - Connection remoteConnection = remoteFactory.createConnection(); + final ActiveMQConnectionFactory remoteFactory = new ActiveMQConnectionFactory(remoteBrokerURI); + final Connection remoteConnection = remoteFactory.createConnection(); remoteConnection.start(); - Session remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer remoteConsumer = remoteSession.createConsumer(destination); + final Session remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer remoteConsumer = remoteSession.createConsumer(destination); Message message = localSession.createTextMessage("test"); localProducer.send(message); @@ -132,31 +129,31 @@ public void testNetworkConnectionReAddURI() throws Exception { LOG.info("testNetworkConnectionReAddURI is starting..."); LOG.info("Adding network connector 'NC1'..."); - NetworkConnector nc = localBroker.addNetworkConnector("static:(" + REMOTE_BROKER_TRANSPORT_URI + ")"); + NetworkConnector nc = localBroker.addNetworkConnector("static:(" + remoteBrokerURI + ")"); nc.setName("NC1"); nc.start(); assertTrue(nc.isStarted()); LOG.info("Looking up network connector by name..."); - NetworkConnector nc1 = localBroker.getNetworkConnectorByName("NC1"); + final NetworkConnector nc1 = localBroker.getNetworkConnectorByName("NC1"); assertNotNull("Should find network connector 'NC1'", nc1); assertTrue(nc1.isStarted()); assertEquals(nc, nc1); LOG.info("Setting up producer and consumer..."); - ActiveMQQueue destination = new ActiveMQQueue(DESTINATION_NAME); + final ActiveMQQueue destination = new ActiveMQQueue(DESTINATION_NAME); - ActiveMQConnectionFactory localFactory = new ActiveMQConnectionFactory(LOCAL_BROKER_TRANSPORT_URI); - Connection localConnection = localFactory.createConnection(); + final ActiveMQConnectionFactory localFactory = new ActiveMQConnectionFactory(localBrokerURI); + final Connection localConnection = localFactory.createConnection(); localConnection.start(); - Session localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer localProducer = localSession.createProducer(destination); + final Session localSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer localProducer = localSession.createProducer(destination); - ActiveMQConnectionFactory remoteFactory = new ActiveMQConnectionFactory(REMOTE_BROKER_TRANSPORT_URI); - Connection remoteConnection = remoteFactory.createConnection(); + final ActiveMQConnectionFactory remoteFactory = new ActiveMQConnectionFactory(remoteBrokerURI); + final Connection remoteConnection = remoteFactory.createConnection(); remoteConnection.start(); - Session remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer remoteConsumer = remoteSession.createConsumer(destination); + final Session remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer remoteConsumer = remoteSession.createConsumer(destination); Message message = localSession.createTextMessage("test"); localProducer.send(message); @@ -172,17 +169,17 @@ public void testNetworkConnectionReAddURI() throws Exception { LOG.info("Removing network connector..."); assertTrue(localBroker.removeNetworkConnector(nc)); - nc1 = localBroker.getNetworkConnectorByName("NC1"); - assertNull("Should not find network connector 'NC1'", nc1); + NetworkConnector lookupNc1 = localBroker.getNetworkConnectorByName("NC1"); + assertNull("Should not find network connector 'NC1'", lookupNc1); LOG.info("Re-adding network connector 'NC2'..."); - nc = localBroker.addNetworkConnector("static:(" + REMOTE_BROKER_TRANSPORT_URI + ")"); + nc = localBroker.addNetworkConnector("static:(" + remoteBrokerURI + ")"); nc.setName("NC2"); nc.start(); assertTrue(nc.isStarted()); LOG.info("Looking up network connector by name..."); - NetworkConnector nc2 = localBroker.getNetworkConnectorByName("NC2"); + final NetworkConnector nc2 = localBroker.getNetworkConnectorByName("NC2"); assertNotNull(nc2); assertTrue(nc2.isStarted()); assertEquals(nc, nc2); @@ -201,8 +198,8 @@ public void testNetworkConnectionReAddURI() throws Exception { LOG.info("Removing network connection 'NC2'"); assertTrue(localBroker.removeNetworkConnector(nc)); - nc2 = localBroker.getNetworkConnectorByName("NC2"); - assertNull("Should not find network connector 'NC2'", nc2); + final NetworkConnector lookupNc2 = localBroker.getNetworkConnectorByName("NC2"); + assertNull("Should not find network connector 'NC2'", lookupNc2); } @Override @@ -212,18 +209,20 @@ protected void setUp() throws Exception { localBroker.setBrokerName("LocalBroker"); localBroker.setUseJmx(false); localBroker.setPersistent(false); - localBroker.setTransportConnectorURIs(new String[]{LOCAL_BROKER_TRANSPORT_URI}); + final TransportConnector localConnector = localBroker.addConnector("tcp://localhost:0"); localBroker.start(); localBroker.waitUntilStarted(); + localBrokerURI = localConnector.getConnectUri(); LOG.info("Setting up RemoteBroker"); remoteBroker = new BrokerService(); remoteBroker.setBrokerName("RemoteBroker"); remoteBroker.setUseJmx(false); remoteBroker.setPersistent(false); - remoteBroker.setTransportConnectorURIs(new String[]{REMOTE_BROKER_TRANSPORT_URI}); + final TransportConnector remoteConnector = remoteBroker.addConnector("tcp://localhost:0"); remoteBroker.start(); remoteBroker.waitUntilStarted(); + remoteBrokerURI = remoteConnector.getConnectUri(); } @Override @@ -242,4 +241,4 @@ protected void tearDown() throws Exception { remoteBroker = null; } } -} \ No newline at end of file +} diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkFailoverTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkFailoverTest.java index f0867532890..b3b67006797 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkFailoverTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkFailoverTest.java @@ -18,13 +18,14 @@ import java.io.IOException; import java.net.URI; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import jakarta.jms.Connection; import jakarta.jms.DeliveryMode; import jakarta.jms.Destination; import jakarta.jms.JMSException; -import jakarta.jms.Message; import jakarta.jms.MessageConsumer; import jakarta.jms.MessageProducer; import jakarta.jms.Queue; @@ -42,6 +43,7 @@ import org.apache.activemq.command.ActiveMQTopic; import org.apache.activemq.transport.TransportFilter; import org.apache.activemq.transport.failover.FailoverTransport; +import org.apache.activemq.util.Wait; import org.apache.activemq.xbean.BrokerFactoryBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,18 +63,31 @@ public class NetworkFailoverTest extends TestCase { protected BrokerService remoteBroker; protected Session localSession; protected Session remoteSession; - protected ActiveMQQueue included=new ActiveMQQueue("include.test.foo"); - private final AtomicInteger replyToNonExistDest = new AtomicInteger(0); - private final AtomicInteger roundTripComplete = new AtomicInteger(0); - private final AtomicInteger remoteDLQCount = new AtomicInteger(0); + protected final ActiveMQQueue included = new ActiveMQQueue("include.test.foo"); + + // Track unique original message texts across outcomes to avoid double-counting + // when duplicates are delivered due to failover and network bridge re-forwarding + private final Set completedMessages = ConcurrentHashMap.newKeySet(); + private final Set nedMessages = ConcurrentHashMap.newKeySet(); + private final Set dlqMessages = ConcurrentHashMap.newKeySet(); public void testRequestReply() throws Exception { final MessageProducer remoteProducer = remoteSession.createProducer(null); - MessageConsumer remoteConsumer = remoteSession.createConsumer(included); + final MessageConsumer remoteConsumer = remoteSession.createConsumer(included); remoteConsumer.setMessageListener(msg -> { final TextMessage textMsg = (TextMessage) msg; + // Extract original text before try block so it's accessible in catch + // (clearBody()/setText() inside try modifies the message body) + String origText; + try { + origText = textMsg.getText(); + } catch (JMSException e) { + LOG.warn("Failed to read original message text", e); + origText = "unknown"; + } + final String originalText = origText; try { - final String payload = "REPLY: " + textMsg.getText() + ", " + textMsg.getJMSMessageID(); + final String payload = "REPLY: " + originalText + ", " + textMsg.getJMSMessageID(); final Destination replyTo = msg.getJMSReplyTo(); textMsg.clearBody(); textMsg.setText(payload); @@ -81,10 +96,11 @@ public void testRequestReply() throws Exception { LOG.info("replied with: " + textMsg.getJMSMessageID()); } catch (DestinationDoesNotExistException expected) { - // been removed but not yet recreated - replyToNonExistDest.incrementAndGet(); + // Temp queue was removed during failover but not yet recreated. + // Track the unique original message text so duplicates don't double-count. try { - LOG.info("NED: " + textMsg.getJMSMessageID()); + nedMessages.add(originalText); + LOG.info("NED: " + textMsg.getJMSMessageID() + ", text: " + originalText); } catch (JMSException e) { e.printStackTrace(); } @@ -94,54 +110,125 @@ public void testRequestReply() throws Exception { } }); - Queue tempQueue = localSession.createTemporaryQueue(); - MessageProducer requestProducer = localSession.createProducer(included); + final Queue tempQueue = localSession.createTemporaryQueue(); + final MessageProducer requestProducer = localSession.createProducer(included); requestProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); - MessageConsumer requestConsumer = localSession.createConsumer(tempQueue); + final MessageConsumer requestConsumer = localSession.createConsumer(tempQueue); - // track remote dlq for forward failures - MessageConsumer dlqconsumer = remoteSession.createConsumer(new ActiveMQQueue(SharedDeadLetterStrategy.DEFAULT_DEAD_LETTER_QUEUE_NAME)); - dlqconsumer.setMessageListener(message -> { + // track remote DLQ for forward failures + final MessageConsumer remoteDlqConsumer = remoteSession.createConsumer( + new ActiveMQQueue(SharedDeadLetterStrategy.DEFAULT_DEAD_LETTER_QUEUE_NAME)); + remoteDlqConsumer.setMessageListener(message -> { try { - LOG.info("dlq " + message.getJMSMessageID()); + if (message instanceof TextMessage) { + dlqMessages.add(((TextMessage) message).getText()); + } + LOG.info("remote dlq " + message.getJMSMessageID()); } catch (JMSException e) { e.printStackTrace(); } - remoteDLQCount.incrementAndGet(); }); - // allow for consumer infos to perculate arround - Thread.sleep(2000); - long done = System.currentTimeMillis() + (MESSAGE_COUNT * 6000); + // Use a separate session for the local DLQ consumer since localSession + // uses synchronous receive() and JMS does not allow mixing synchronous + // receive with asynchronous MessageListener on the same session + final Session localDlqSession = localConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer localDlqConsumer = localDlqSession.createConsumer( + new ActiveMQQueue(SharedDeadLetterStrategy.DEFAULT_DEAD_LETTER_QUEUE_NAME)); + localDlqConsumer.setMessageListener(message -> { + try { + if (message instanceof TextMessage) { + dlqMessages.add(((TextMessage) message).getText()); + } + LOG.info("local dlq " + message.getJMSMessageID()); + } catch (JMSException e) { + e.printStackTrace(); + } + }); + + // Wait for both network bridges to be fully started + waitForBridgeFullyStarted(localBroker, "local"); + waitForBridgeFullyStarted(remoteBroker, "remote"); + + // Wait for the remote consumer demand to propagate to the local broker + // so messages sent to 'included' on local broker are forwarded to remote + assertTrue("Network consumer for included queue should be registered on local broker", + Wait.waitFor(() -> { + try { + return localBroker.getDestination(included) + .getConsumers().size() >= 1; + } catch (Exception e) { + return false; + } + }, TimeUnit.SECONDS.toMillis(10), 100)); + + final FailoverTransport failoverTransport = ((FailoverTransport) ((TransportFilter) ((TransportFilter) + ((ActiveMQConnection) localConnection) + .getTransport()).getNext()).getNext()); + + final long done = System.currentTimeMillis() + (MESSAGE_COUNT * 6000); int i = 0; - while (MESSAGE_COUNT > roundTripComplete.get() + remoteDLQCount.get() + replyToNonExistDest.get() - && done > System.currentTimeMillis()) { - if ( i < MESSAGE_COUNT) { - String payload = "test msg " + i; + while (uniqueAccountedCount() < MESSAGE_COUNT && done > System.currentTimeMillis()) { + if (i < MESSAGE_COUNT) { + final String payload = "test msg " + i; i++; - TextMessage msg = localSession.createTextMessage(payload); + final TextMessage msg = localSession.createTextMessage(payload); msg.setJMSReplyTo(tempQueue); requestProducer.send(msg); - LOG.info("Sent: " + msg.getJMSMessageID() +", Failing over"); - ((FailoverTransport) ((TransportFilter) ((TransportFilter) - ((ActiveMQConnection) localConnection) - .getTransport()).getNext()).getNext()) - .handleTransportFailure(new IOException("Forcing failover from test")); + LOG.info("Sent: " + msg.getJMSMessageID() + ", Failing over"); + failoverTransport.handleTransportFailure(new IOException("Forcing failover from test")); + + // Wait for the failover transport to reconnect before attempting to receive + assertTrue("Failover transport should reconnect", + Wait.waitFor(failoverTransport::isConnected, + TimeUnit.SECONDS.toMillis(10), 100)); } - TextMessage result = (TextMessage)requestConsumer.receive(5000); + final TextMessage result = (TextMessage) requestConsumer.receive(5000); if (result != null) { LOG.info("Got reply: " + result.getJMSMessageID() + ", " + result.getText()); - roundTripComplete.incrementAndGet(); + // Extract original message text from reply ("REPLY: test msg N, ID:...") + final String replyText = result.getText(); + final int startIdx = replyText.indexOf("test msg"); + if (startIdx >= 0) { + final int endIdx = replyText.indexOf(',', startIdx); + completedMessages.add(replyText.substring(startIdx, endIdx > startIdx ? endIdx : replyText.length())); + } } } - LOG.info("complete: " + roundTripComplete.get() - + ", remoteDLQCount: " + remoteDLQCount.get() - + ", replyToNonExistDest: " + replyToNonExistDest.get()); - assertEquals("complete:" + roundTripComplete.get() - + ", remoteDLQCount: " + remoteDLQCount.get() - + ", replyToNonExistDest: " + replyToNonExistDest.get(), - MESSAGE_COUNT, roundTripComplete.get() + remoteDLQCount.get() + replyToNonExistDest.get() ); + // Wait for async processing (DLQ delivery, NED processing) to complete + assertTrue("All " + MESSAGE_COUNT + " unique messages should be accounted for", + Wait.waitFor(() -> { + final int total = uniqueAccountedCount(); + LOG.info("Waiting: completed=" + completedMessages.size() + + ", NED=" + nedMessages.size() + + ", DLQ=" + dlqMessages.size() + + ", uniqueTotal=" + total); + return total >= MESSAGE_COUNT; + }, TimeUnit.SECONDS.toMillis(30), 500)); + + LOG.info("Final: completed=" + completedMessages.size() + + ", NED=" + nedMessages.size() + + ", DLQ=" + dlqMessages.size() + + ", uniqueTotal=" + uniqueAccountedCount()); + assertTrue("All " + MESSAGE_COUNT + " unique messages should be accounted for " + + "(completed=" + completedMessages.size() + + ", NED=" + nedMessages.size() + + ", DLQ=" + dlqMessages.size() + ")", + uniqueAccountedCount() >= MESSAGE_COUNT); + } + + /** + * Returns the number of unique messages accounted for across all outcomes. + * A message is counted once even if it was delivered multiple times due to + * failover (as round-trip completed, NED, or DLQ). + */ + private int uniqueAccountedCount() { + final Set all = ConcurrentHashMap.newKeySet(); + all.addAll(completedMessages); + all.addAll(nedMessages); + all.addAll(dlqMessages); + return all.size(); } @Override @@ -160,14 +247,14 @@ protected void doTearDown() throws Exception { try { localConnection.close(); remoteConnection.close(); - } catch(Exception ex) {} + } catch (Exception ex) {} try { localBroker.stop(); - } catch(Exception ex) {} + } catch (Exception ex) {} try { remoteBroker.stop(); - } catch(Exception ex) {} + } catch (Exception ex) {} } protected void doSetUp(final boolean deleteAllMessages) throws Exception { @@ -210,13 +297,21 @@ protected void doSetUp(final boolean deleteAllMessages) throws Exception { remoteBroker.addNetworkConnector(remoteToLocal); remoteBroker.startNetworkConnector(remoteToLocal, null); - ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory("failover:(" + localURI + "," + remoteURI + ")?randomize=false&backup=false&trackMessages=true"); - localConnection = fac.createConnection(); + final ActiveMQConnectionFactory localFac = new ActiveMQConnectionFactory( + "failover:(" + localURI + "," + remoteURI + ")?randomize=false&backup=false&trackMessages=true"); + localConnection = localFac.createConnection(); localConnection.setClientID("local"); localConnection.start(); - fac = new ActiveMQConnectionFactory("failover:(" + remoteURI + "," + localURI + ")?randomize=false&backup=false&trackMessages=true"); - fac.setWatchTopicAdvisories(false); - remoteConnection = fac.createConnection(); + + // The remote connection does not need trackMessages since we only force failover + // on the local connection. Disable duplicate checking so that messages re-forwarded + // by the network bridge (due to forced failovers) are delivered to the remote consumer + // listener instead of being silently poison-acked as duplicates. + final ActiveMQConnectionFactory remoteFac = new ActiveMQConnectionFactory( + "failover:(" + remoteURI + "," + localURI + ")?randomize=false&backup=false"); + remoteFac.setWatchTopicAdvisories(false); + remoteFac.setCheckForDuplicates(false); + remoteConnection = remoteFac.createConnection(); remoteConnection.setClientID("remote"); remoteConnection.start(); @@ -232,14 +327,25 @@ protected String getLocalBrokerURI() { return "org/apache/activemq/network/localBroker-ephemeral.xml"; } - protected BrokerService createBroker(String uri) throws Exception { - Resource resource = new ClassPathResource(uri); - BrokerFactoryBean factory = new BrokerFactoryBean(resource); - resource = new ClassPathResource(uri); - factory = new BrokerFactoryBean(resource); + protected void waitForBridgeFullyStarted(final BrokerService broker, final String label) throws Exception { + assertTrue(label + " broker bridge should be fully started", Wait.waitFor(() -> { + if (broker.getNetworkConnectors().isEmpty() + || broker.getNetworkConnectors().get(0).activeBridges().isEmpty()) { + return false; + } + final NetworkBridge bridge = broker.getNetworkConnectors().get(0).activeBridges().iterator().next(); + if (bridge instanceof DemandForwardingBridgeSupport) { + return ((DemandForwardingBridgeSupport) bridge).startedLatch.getCount() == 0; + } + return true; + }, TimeUnit.SECONDS.toMillis(10), 100)); + } + + protected BrokerService createBroker(final String uri) throws Exception { + final Resource resource = new ClassPathResource(uri); + final BrokerFactoryBean factory = new BrokerFactoryBean(resource); factory.afterPropertiesSet(); - BrokerService result = factory.getBroker(); - return result; + return factory.getBroker(); } protected BrokerService createLocalBroker() throws Exception { diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRemovesSubscriptionsTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRemovesSubscriptionsTest.java index 5369b45801b..e9426b0ecfd 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRemovesSubscriptionsTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRemovesSubscriptionsTest.java @@ -16,8 +16,9 @@ */ package org.apache.activemq.network; -import jakarta.jms.Message; -import jakarta.jms.MessageListener; +import java.net.URI; +import java.util.concurrent.TimeUnit; + import jakarta.jms.Session; import jakarta.jms.TopicConnection; import jakarta.jms.TopicSession; @@ -25,8 +26,10 @@ import junit.framework.TestCase; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.broker.TransportConnector; import org.apache.activemq.broker.region.Destination; import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; /** * Various Tests to show the memory leak suspect in network of brokers. This is @@ -34,89 +37,72 @@ * */ public class NetworkRemovesSubscriptionsTest extends TestCase { - private final static String frontEndAddress = "tcp://0.0.0.0:61617"; - private final static String backEndAddress = "tcp://0.0.0.0:61616"; - private final static String TOPIC_NAME = "TEST_TOPIC"; + private static final String TOPIC_NAME = "TEST_TOPIC"; + private final ActiveMQTopic topic = new ActiveMQTopic(TOPIC_NAME); private BrokerService frontEnd; private BrokerService backEnd; - private final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(frontEndAddress); - private final ActiveMQTopic topic = new ActiveMQTopic(TOPIC_NAME); + private ActiveMQConnectionFactory connectionFactory; public void testWithSessionAndSubsciberClose() throws Exception { - TopicConnection connection = connectionFactory.createTopicConnection(); + final TopicConnection connection = connectionFactory.createTopicConnection(); connection.start(); for (int i = 0; i < 100; i++) { - TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); - DummyMessageListener listener = new DummyMessageListener(); - subscriber.setMessageListener(listener); + final TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); + subscriber.setMessageListener(msg -> { }); subscriber.close(); subscriberSession.close(); } connection.close(); - Thread.sleep(1000); - Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); - assertNotNull(dest); - assertTrue(dest.getConsumers().isEmpty()); + assertBackEndConsumersEmpty(); } public void testWithSessionCloseOutsideTheLoop() throws Exception { - TopicConnection connection = connectionFactory.createTopicConnection(); + final TopicConnection connection = connectionFactory.createTopicConnection(); connection.start(); - TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); for (int i = 0; i < 100; i++) { - TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); - DummyMessageListener listener = new DummyMessageListener(); - subscriber.setMessageListener(listener); + final TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); + subscriber.setMessageListener(msg -> { }); subscriber.close(); } subscriberSession.close(); connection.close(); - Thread.sleep(1000); - Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); - assertNotNull(dest); - assertTrue(dest.getConsumers().isEmpty()); + assertBackEndConsumersEmpty(); } public void testWithOneSubscriber() throws Exception { - TopicConnection connection = connectionFactory.createTopicConnection(); + final TopicConnection connection = connectionFactory.createTopicConnection(); connection.start(); - TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); - DummyMessageListener listener = new DummyMessageListener(); - subscriber.setMessageListener(listener); + final TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); + subscriber.setMessageListener(msg -> { }); subscriber.close(); subscriberSession.close(); connection.close(); - Thread.sleep(1000); - Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); - assertNotNull(dest); - assertTrue(dest.getConsumers().isEmpty()); + assertBackEndConsumersEmpty(); } public void testWithoutSessionAndSubsciberClose() throws Exception { - TopicConnection connection = connectionFactory.createTopicConnection(); + final TopicConnection connection = connectionFactory.createTopicConnection(); connection.start(); for (int i = 0; i < 100; i++) { - TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); + final TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); assertNotNull(subscriber); } connection.close(); - Thread.sleep(1000); - Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); - assertNotNull(dest); - assertTrue(dest.getConsumers().isEmpty()); + assertBackEndConsumersEmpty(); } /** @@ -126,14 +112,13 @@ public void testWithoutSessionAndSubsciberClose() throws Exception { */ public void testWithoutSessionAndSubsciberClosePlayAround() throws Exception { - TopicConnection connection = connectionFactory.createTopicConnection(); + final TopicConnection connection = connectionFactory.createTopicConnection(); connection.start(); for (int i = 0; i < 100; i++) { - TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); - DummyMessageListener listener = new DummyMessageListener(); - subscriber.setMessageListener(listener); + final TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + final TopicSubscriber subscriber = subscriberSession.createSubscriber(topic); + subscriber.setMessageListener(msg -> { }); if (i != 50) { subscriber.close(); subscriberSession.close(); @@ -141,19 +126,14 @@ public void testWithoutSessionAndSubsciberClosePlayAround() throws Exception { } connection.close(); - Thread.sleep(1000); - Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); - assertNotNull(dest); - assertTrue(dest.getConsumers().isEmpty()); + assertBackEndConsumersEmpty(); } - class DummyMessageListener implements MessageListener { - - @Override - public void onMessage(Message arg0) { - // TODO Auto-generated method stub - - } + private void assertBackEndConsumersEmpty() throws Exception { + assertTrue("backEnd consumers should be empty", Wait.waitFor(() -> { + final Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic); + return dest != null && dest.getConsumers().isEmpty(); + }, TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); } @Override @@ -161,20 +141,43 @@ protected void setUp() throws Exception { this.backEnd = new BrokerService(); this.backEnd.setBrokerName("backEnd"); this.backEnd.setPersistent(false); - NetworkConnector backEndNetwork = this.backEnd.addNetworkConnector("static://" + frontEndAddress); - backEndNetwork.setName("backEndNetwork"); - backEndNetwork.setDynamicOnly(true); - this.backEnd.addConnector(backEndAddress); + final TransportConnector backEndConnector = this.backEnd.addConnector("tcp://localhost:0"); this.backEnd.start(); + this.backEnd.waitUntilStarted(); + + final URI backEndConnectURI = backEndConnector.getConnectUri(); this.frontEnd = new BrokerService(); this.frontEnd.setBrokerName("frontEnd"); this.frontEnd.setPersistent(false); - NetworkConnector frontEndNetwork = this.frontEnd.addNetworkConnector("static://" + backEndAddress); - frontEndNetwork.setName("frontEndNetwork"); - this.frontEnd.addConnector(frontEndAddress); + final TransportConnector frontEndConnector = this.frontEnd.addConnector("tcp://localhost:0"); this.frontEnd.start(); - Thread.sleep(2000); + this.frontEnd.waitUntilStarted(); + + final URI frontEndConnectURI = frontEndConnector.getConnectUri(); + + // Add network connectors using actual assigned ephemeral ports + final NetworkConnector backEndNetwork = this.backEnd.addNetworkConnector("static://" + frontEndConnectURI); + backEndNetwork.setName("backEndNetwork"); + backEndNetwork.setDynamicOnly(true); + backEndNetwork.start(); + + final NetworkConnector frontEndNetwork = this.frontEnd.addNetworkConnector("static://" + backEndConnectURI); + frontEndNetwork.setName("frontEndNetwork"); + frontEndNetwork.start(); + + // Wait for both network bridges to be fully started + assertTrue("backEnd bridge should start", Wait.waitFor(() -> + !this.backEnd.getNetworkConnectors().isEmpty() + && !this.backEnd.getNetworkConnectors().get(0).activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); + + assertTrue("frontEnd bridge should start", Wait.waitFor(() -> + !this.frontEnd.getNetworkConnectors().isEmpty() + && !this.frontEnd.getNetworkConnectors().get(0).activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); + + this.connectionFactory = new ActiveMQConnectionFactory(frontEndConnectURI); } @Override diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartPlainTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartPlainTest.java index 79f15f863e7..75a42b2136d 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartPlainTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartPlainTest.java @@ -16,9 +16,13 @@ */ package org.apache.activemq.network; +/** + * Variant of {@link NetworkRestartTest} that uses a plain network connector + * without destination filtering (no dynamicallyIncludedDestinations or excludedDestinations). + */ public class NetworkRestartPlainTest extends NetworkRestartTest { @Override - protected String getLocalBrokerURI() { - return "org/apache/activemq/network/localBroker-plain.xml"; + protected void configureNetworkConnector(final DiscoveryNetworkConnector networkConnector) { + // Plain mode: no destination filtering, just use defaults } } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartTest.java index 9d9460647ab..6bcb2444110 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/network/NetworkRestartTest.java @@ -16,17 +16,25 @@ */ package org.apache.activemq.network; +import java.net.URI; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import jakarta.jms.Connection; +import jakarta.jms.Message; +import jakarta.jms.MessageConsumer; +import jakarta.jms.MessageProducer; +import jakarta.jms.Session; +import jakarta.jms.TextMessage; + import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.TestSupport; import org.apache.activemq.broker.BrokerService; import org.apache.activemq.command.ActiveMQQueue; -import org.apache.activemq.xbean.BrokerFactoryBean; +import org.apache.activemq.command.ActiveMQTopic; +import org.apache.activemq.util.Wait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; - -import jakarta.jms.*; public class NetworkRestartTest extends TestSupport { @@ -39,77 +47,84 @@ public class NetworkRestartTest extends TestSupport { protected Session localSession; protected Session remoteSession; - protected ActiveMQQueue included=new ActiveMQQueue("include.test.foo"); - + protected final ActiveMQQueue included = new ActiveMQQueue("include.test.foo"); public void testConnectorRestart() throws Exception { - MessageConsumer remoteConsumer = remoteSession.createConsumer(included); - MessageProducer localProducer = localSession.createProducer(included); + final MessageConsumer remoteConsumer = remoteSession.createConsumer(included); + final MessageProducer localProducer = localSession.createProducer(included); localProducer.send(localSession.createTextMessage("before")); - Message before = remoteConsumer.receive(1000); + final Message before = remoteConsumer.receive(5000); assertNotNull(before); - assertEquals("before", ((TextMessage)before).getText()); - - // restart connector + assertEquals("before", ((TextMessage) before).getText()); - // wait for ack back to localbroker with concurrent store and dispatch, dispatch occurs first - Thread.sleep(1000); + // Wait for the network connector bridge to be fully established before stopping + final NetworkConnector connector = localBroker.getNetworkConnectorByName("networkConnector"); + assertNotNull("networkConnector must exist", connector); - NetworkConnector connector = localBroker.getNetworkConnectorByName("networkConnector"); + assertTrue("bridge should be active before stop", + Wait.waitFor(() -> !connector.activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); LOG.info("Stopping connector"); connector.stop(); - Thread.sleep(5000); + // Wait until the connector has fully stopped (no active bridges) + assertTrue("bridge should stop", + Wait.waitFor(() -> connector.activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); + LOG.info("Starting connector"); connector.start(); - Thread.sleep(5000); - + // Wait until the bridge is re-established and fully started + waitForBridgeFullyStarted(connector); localProducer.send(localSession.createTextMessage("after")); - Message after = remoteConsumer.receive(3000); - assertNotNull(after); - assertEquals("after", ((TextMessage)after).getText()); - + final Message after = remoteConsumer.receive(5000); + assertNotNull("should receive message after connector restart", after); + assertEquals("after", ((TextMessage) after).getText()); } public void testConnectorReAdd() throws Exception { - MessageConsumer remoteConsumer = remoteSession.createConsumer(included); - MessageProducer localProducer = localSession.createProducer(included); + final MessageConsumer remoteConsumer = remoteSession.createConsumer(included); + final MessageProducer localProducer = localSession.createProducer(included); localProducer.send(localSession.createTextMessage("before")); - Message before = remoteConsumer.receive(1000); + final Message before = remoteConsumer.receive(5000); assertNotNull(before); - assertEquals("before", ((TextMessage)before).getText()); - - // restart connector + assertEquals("before", ((TextMessage) before).getText()); - // wait for ack back to localbroker with concurrent store and dispatch, dispatch occurs first - Thread.sleep(1000); + // Wait for the network connector bridge to be fully established before removing + final NetworkConnector connector = localBroker.getNetworkConnectorByName("networkConnector"); + assertNotNull("networkConnector must exist", connector); - NetworkConnector connector = localBroker.getNetworkConnectorByName("networkConnector"); + assertTrue("bridge should be active before remove", + Wait.waitFor(() -> !connector.activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); LOG.info("Removing connector"); connector.stop(); localBroker.removeNetworkConnector(connector); - Thread.sleep(5000); + // Wait until the connector has fully stopped + assertTrue("bridge should stop after removal", + Wait.waitFor(() -> connector.activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(100))); + LOG.info("Re-adding connector"); localBroker.addNetworkConnector(connector); connector.start(); - Thread.sleep(5000); - + // Wait until the bridge is re-established and fully started + waitForBridgeFullyStarted(connector); localProducer.send(localSession.createTextMessage("after")); - Message after = remoteConsumer.receive(3000); - assertNotNull(after); - assertEquals("after", ((TextMessage)after).getText()); + final Message after = remoteConsumer.receive(5000); + assertNotNull("should receive message after connector re-add", after); + assertEquals("after", ((TextMessage) after).getText()); } - protected void setUp() throws Exception { setAutoFail(true); super.setUp(); @@ -133,26 +148,33 @@ protected void doTearDown() throws Exception { } protected void doSetUp() throws Exception { - remoteBroker = createRemoteBroker(); remoteBroker.setDeleteAllMessagesOnStartup(true); remoteBroker.start(); remoteBroker.waitUntilStarted(); - localBroker = createLocalBroker(); + + final URI remoteConnectUri = remoteBroker.getTransportConnectorByScheme("tcp").getConnectUri(); + + localBroker = createLocalBroker(remoteConnectUri); localBroker.setDeleteAllMessagesOnStartup(true); localBroker.start(); localBroker.waitUntilStarted(); - String localURI = "tcp://localhost:61616"; - String remoteURI = "tcp://localhost:61617"; - ActiveMQConnectionFactory fac = new ActiveMQConnectionFactory(localURI); - localConnection = fac.createConnection(); + final URI localConnectUri = localBroker.getTransportConnectorByScheme("tcp").getConnectUri(); + + // Wait for the network bridge to be fully started before creating connections + final NetworkConnector nc = localBroker.getNetworkConnectorByName("networkConnector"); + assertNotNull("networkConnector should exist after broker start", nc); + waitForBridgeFullyStarted(nc); + + final ActiveMQConnectionFactory localFac = new ActiveMQConnectionFactory(localConnectUri); + localConnection = localFac.createConnection(); localConnection.setClientID("local"); localConnection.start(); - fac = new ActiveMQConnectionFactory(remoteURI); - fac.setWatchTopicAdvisories(false); - remoteConnection = fac.createConnection(); + final ActiveMQConnectionFactory remoteFac = new ActiveMQConnectionFactory(remoteConnectUri); + remoteFac.setWatchTopicAdvisories(false); + remoteConnection = remoteFac.createConnection(); remoteConnection.setClientID("remote"); remoteConnection.start(); @@ -160,30 +182,62 @@ protected void doSetUp() throws Exception { remoteSession = remoteConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); } - protected String getRemoteBrokerURI() { - return "org/apache/activemq/network/remoteBroker.xml"; + protected BrokerService createRemoteBroker() throws Exception { + final BrokerService broker = new BrokerService(); + broker.setBrokerName("remoteBroker"); + broker.setUseJmx(false); + broker.setPersistent(true); + broker.setUseShutdownHook(false); + broker.setMonitorConnectionSplits(false); + broker.addConnector("tcp://localhost:0"); + return broker; } - protected String getLocalBrokerURI() { - return "org/apache/activemq/network/localBroker.xml"; + protected BrokerService createLocalBroker(final URI remoteUri) throws Exception { + final BrokerService broker = new BrokerService(); + broker.setBrokerName("localBroker"); + broker.setPersistent(true); + broker.setUseShutdownHook(false); + broker.setMonitorConnectionSplits(true); + broker.addConnector("tcp://localhost:0"); + + final DiscoveryNetworkConnector networkConnector = new DiscoveryNetworkConnector( + new URI("static:(" + remoteUri + ")")); + networkConnector.setName("networkConnector"); + configureNetworkConnector(networkConnector); + broker.addNetworkConnector(networkConnector); + + return broker; } - protected BrokerService createBroker(String uri) throws Exception { - Resource resource = new ClassPathResource(uri); - BrokerFactoryBean factory = new BrokerFactoryBean(resource); - resource = new ClassPathResource(uri); - factory = new BrokerFactoryBean(resource); - factory.afterPropertiesSet(); - BrokerService result = factory.getBroker(); - return result; + /** + * Configure the network connector. Subclasses can override to customize + * (e.g., remove destination filtering for plain mode). + */ + protected void configureNetworkConnector(final DiscoveryNetworkConnector networkConnector) { + networkConnector.setDynamicOnly(false); + networkConnector.setConduitSubscriptions(true); + networkConnector.setDecreaseNetworkConsumerPriority(false); + networkConnector.setDynamicallyIncludedDestinations( + List.of(new ActiveMQQueue("include.test.foo"), + new ActiveMQTopic("include.test.bar"))); + networkConnector.setExcludedDestinations( + List.of(new ActiveMQQueue("exclude.test.foo"), + new ActiveMQTopic("exclude.test.bar"))); } - protected BrokerService createLocalBroker() throws Exception { - return createBroker(getLocalBrokerURI()); + private void waitForBridgeFullyStarted(final NetworkConnector connector) throws Exception { + assertTrue("bridge should be fully started", + Wait.waitFor(() -> { + for (final NetworkBridge bridge : connector.activeBridges()) { + if (bridge instanceof DemandForwardingBridgeSupport) { + final DemandForwardingBridgeSupport dfBridge = (DemandForwardingBridgeSupport) bridge; + if (dfBridge.startedLatch.getCount() == 0) { + return true; + } + } + } + return false; + }, TimeUnit.SECONDS.toMillis(15), TimeUnit.MILLISECONDS.toMillis(100))); } - - protected BrokerService createRemoteBroker() throws Exception { - return createBroker(getRemoteBrokerURI()); - } - } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/network/VirtualConsumerDemandTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/network/VirtualConsumerDemandTest.java index 4c9b03e7f90..31aee0938db 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/network/VirtualConsumerDemandTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/network/VirtualConsumerDemandTest.java @@ -126,8 +126,7 @@ public void testVirtualTopics() throws Exception { MessageProducer includedProducer = localSession.createProducer(new ActiveMQTopic("VirtualTopic.include.test.bar")); MessageProducer includedProducer2 = localSession.createProducer(new ActiveMQTopic("VirtualTopic.include.test.bar2")); MessageProducer includedProducer3 = localSession.createProducer(new ActiveMQTopic("VirtualTopic.include.test.bar3")); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(new ActiveMQTopic("VirtualTopic.include.test.bar")).getDestinationStatistics(); final DestinationStatistics destinationStatistics2 = localBroker.getDestination(new ActiveMQTopic("VirtualTopic.include.test.bar2")).getDestinationStatistics(); @@ -157,9 +156,9 @@ public void testVirtualTopics() throws Exception { assertRemoteAdvisoryCount(advisoryConsumer, 2); assertAdvisoryBrokerCounts(1,2,2); - //should not have forwarded for 3rd topic - Thread.sleep(1000); - assertEquals("local broker dest stat dispatched", 0, destinationStatistics3.getDispatched().getCount()); + //should not have forwarded for 3rd topic - verify no dispatch occurs + assertTrue("should not forward for 3rd topic without queue destination", + !Wait.waitFor(() -> destinationStatistics3.getDispatched().getCount() > 0, 2000, 100)); } @@ -175,11 +174,10 @@ public void testVirtualTopicWithConsumer() throws Exception { doSetUp(true, null); //use just the default virtual topic setup - MessageConsumer advisoryConsumer = getVirtualDestinationAdvisoryConsumer("VirtualTopic.>"); + final MessageConsumer advisoryConsumer = getVirtualDestinationAdvisoryConsumer("VirtualTopic.>"); - MessageProducer includedProducer = localSession.createProducer(new ActiveMQTopic("VirtualTopic.include.test.bar")); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(new ActiveMQTopic("VirtualTopic.include.test.bar")); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(new ActiveMQTopic("VirtualTopic.include.test.bar")).getDestinationStatistics(); @@ -213,15 +211,14 @@ public void testVirtualTopicWithConsumerGoOffline() throws Exception { Assume.assumeTrue(isUseVirtualDestSubsOnCreation); //use just the default virtual topic setup doSetUp(true, null); - MessageConsumer advisoryConsumer = getVirtualDestinationAdvisoryConsumer("VirtualTopic.>"); + final MessageConsumer advisoryConsumer = getVirtualDestinationAdvisoryConsumer("VirtualTopic.>"); - MessageProducer includedProducer = localSession.createProducer(new ActiveMQTopic("VirtualTopic.include.test.bar")); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(new ActiveMQTopic("VirtualTopic.include.test.bar")); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(new ActiveMQTopic("VirtualTopic.include.test.bar")).getDestinationStatistics(); - MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("Consumer.cons1.VirtualTopic.include.test.bar")); + final MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("Consumer.cons1.VirtualTopic.include.test.bar")); waitForConsumerCount(destinationStatistics, 1); includedProducer.send(test); @@ -232,8 +229,8 @@ public void testVirtualTopicWithConsumerGoOffline() throws Exception { assertLocalBrokerStatistics(destinationStatistics, 1); //close the consumer and send a second message + //with isUseVirtualDestSubsOnCreation, demand persists even without consumer bridgeConsumer.close(); - Thread.sleep(2000); includedProducer.send(test); //check that the message was forwarded @@ -281,9 +278,8 @@ protected void testDynamicFlow(boolean forceDurable) throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); final DestinationStatistics remoteDestStatistics = remoteBroker.getDestination( @@ -346,17 +342,14 @@ public void testSecondNonIncludedCompositeTopicForwardSameQueue() throws Excepti runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - Thread.sleep(2000); - //add one that is included - CompositeTopic compositeTopic2 = createCompositeTopic(testTopicName, + final CompositeTopic compositeTopic2 = createCompositeTopic(testTopicName, new ActiveMQQueue("include.test.bar.bridge")); runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic, compositeTopic2}, true); - Thread.sleep(2000); - MessageProducer includedProducer = localSession.createProducer(included); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); final DestinationStatistics remoteDestStatistics = remoteBroker.getDestination( @@ -396,17 +389,14 @@ public void testSecondNonIncludedCompositeTopic() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - Thread.sleep(2000); - //add one that is included - CompositeTopic compositeTopic2 = createCompositeTopic(testTopicName, + final CompositeTopic compositeTopic2 = createCompositeTopic(testTopicName, new ActiveMQQueue("include.test.bar.bridge")); runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic, compositeTopic2}, true); - Thread.sleep(2000); - MessageProducer includedProducer = localSession.createProducer(included); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); final DestinationStatistics remoteDestStatistics = remoteBroker.getDestination( @@ -446,18 +436,20 @@ public void testNoUseVirtualDestinationSubscriptionsOnCreation() throws Exceptio runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); final DestinationStatistics remoteDestStatistics = remoteBroker.getDestination( new ActiveMQQueue("include.test.bar.bridge")).getDestinationStatistics(); includedProducer.send(test); - Thread.sleep(2000); - waitForDispatchFromLocalBroker(destinationStatistics, 0); + //verify no messages are forwarded - negative test + assertTrue("should not forward without useVirtualDestSubsOnCreation", + !Wait.waitFor(() -> destinationStatistics.getDispatched().getCount() > 0 + || remoteDestStatistics.getMessages().getCount() > 0, 2000, 100)); + assertLocalBrokerStatistics(destinationStatistics, 0); assertEquals("remote dest messages", 0, remoteDestStatistics.getMessages().getCount()); @@ -488,9 +480,8 @@ public void testTwoTargetsRemove1() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); final DestinationStatistics remoteDestStatistics = remoteBroker.getDestination( @@ -498,10 +489,18 @@ public void testTwoTargetsRemove1() throws Exception { final DestinationStatistics remoteDestStatistics2 = remoteBroker.getDestination( new ActiveMQQueue("include.test.bar.bridge2")).getDestinationStatistics(); - Thread.sleep(2000); + //wait for advisory broker to register virtual destination consumers + assertTrue("advisory broker counts not ready", + Wait.waitFor(() -> { + try { + assertAdvisoryBrokerCounts(1,2,2); + return true; + } catch (AssertionError | Exception e) { + return false; + } + }, 10000, 200)); //two advisory messages sent for each target when destinations are created assertRemoteAdvisoryCount(advisoryConsumer, 2); - assertAdvisoryBrokerCounts(1,2,2); waitForConsumerCount(destinationStatistics, 1); @@ -517,7 +516,22 @@ public void testTwoTargetsRemove1() throws Exception { new ActiveMQQueue("include.test.bar.bridge")); runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - Thread.sleep(2000); + //wait for virtual destination update to propagate + assertTrue("advisory broker counts not updated after removing target", + Wait.waitFor(() -> { + try { + assertAdvisoryBrokerCounts(1,1,1); + return true; + } catch (AssertionError | Exception e) { + return false; + } + }, 10000, 200)); + + //wait for the local broker's bridge to process the virtual destination update; + //the bridge removes the old demand subscription before adding the new one, + //so the consumer count transitions 1 -> 0 -> 1 + Wait.waitFor(() -> destinationStatistics.getConsumers().getCount() == 0, 5000, 100); + waitForConsumerCount(destinationStatistics, 1); includedProducer.send(test); @@ -575,11 +589,19 @@ public void testTwoTargetsRemove1Destination() throws Exception { assertEquals("remote2 dest messages", 1, remoteDestStatistics2.getMessages().getCount()); remoteBroker.removeDestination(new ActiveMQQueue("include.test.bar.bridge2")); - Thread.sleep(2000); + //wait for destination removal to propagate + assertTrue("advisory broker counts not updated after destination removal", + Wait.waitFor(() -> { + try { + assertAdvisoryBrokerCounts(1,1,1); + return true; + } catch (AssertionError | Exception e) { + return false; + } + }, 10000, 200)); //2 for each target queue destination in the virtual subscription //1 for the removal of a queue assertRemoteAdvisoryCount(advisoryConsumer, 3); - assertAdvisoryBrokerCounts(1,1,1); includedProducer.send(test); @@ -616,9 +638,8 @@ public void testTwoCompositeTopicsRemove1() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic1, compositeTopic2}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Message test = localSession.createTextMessage("test"); - Thread.sleep(1000); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); final DestinationStatistics remoteDestStatistics = remoteBroker.getDestination( @@ -635,9 +656,16 @@ public void testTwoCompositeTopicsRemove1() throws Exception { //verify there are 2 virtual destinations but only 1 consumer and broker dest assertAdvisoryBrokerCounts(2,1,1); runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic1}, true); - Thread.sleep(2000); //verify there is is only 1 virtual dest after deletion - assertAdvisoryBrokerCounts(1,1,1); + assertTrue("virtual destination count not updated after removal", + Wait.waitFor(() -> { + try { + assertAdvisoryBrokerCounts(1,1,1); + return true; + } catch (AssertionError | Exception e) { + return false; + } + }, 10000, 200)); includedProducer.send(test); @@ -734,10 +762,13 @@ public void testDestinationAddedFirst() throws Exception { remoteBroker.getBroker().addDestination(remoteBroker.getAdminConnectionContext(), new ActiveMQQueue("include.test.bar.bridge"), false); - Thread.sleep(2000); + assertTrue("remote destination not ready", + Wait.waitFor(() -> remoteBroker.getDestination(new ActiveMQQueue("include.test.bar.bridge")) != null, + 10000, 200)); + //configure a virtual destination that forwards messages from topic testQueueName //to queue "include.test.bar.bridge" - CompositeTopic compositeTopic = createCompositeTopic(testTopicName, + final CompositeTopic compositeTopic = createCompositeTopic(testTopicName, new ActiveMQQueue("include.test.bar.bridge")); final DestinationStatistics remoteDestStatistics = remoteBroker.getDestination( @@ -745,9 +776,8 @@ public void testDestinationAddedFirst() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Message test = localSession.createTextMessage("test"); - Thread.sleep(1000); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); @@ -783,22 +813,16 @@ public void testWithConsumer() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Message test = localSession.createTextMessage("test"); - Thread.sleep(1000); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); - MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - //should only be 1 because of conduit subs even though there is 2 consumers - //for the case where isUseVirtualDestSubsOnCreation is true, - //1 for the composite destination creation and 1 for the actual consumer - return 1 == destinationStatistics.getConsumers().getCount(); - } - }); + final MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); + //should only be 1 because of conduit subs even though there is 2 consumers + //for the case where isUseVirtualDestSubsOnCreation is true, + //1 for the composite destination creation and 1 for the actual consumer + waitForConsumerCount(destinationStatistics, 1); includedProducer.send(test); assertNotNull(bridgeConsumer.receive(5000)); @@ -837,14 +861,13 @@ public void testWith2ConsumersRemove1() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Message test = localSession.createTextMessage("test"); - Thread.sleep(1000); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); - MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); - MessageConsumer bridgeConsumer2 = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); + final MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); + final MessageConsumer bridgeConsumer2 = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); //should only be 1 because of conduit subs even though there is 2 consumers //for the case where isUseVirtualDestSubsOnCreation is true, @@ -895,14 +918,13 @@ public void testWith2ConsumersRemoveBoth() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Message test = localSession.createTextMessage("test"); - Thread.sleep(1000); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); - MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); - MessageConsumer bridgeConsumer2 = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); + final MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); + final MessageConsumer bridgeConsumer2 = remoteSession.createConsumer(new ActiveMQQueue("include.test.bar.bridge")); //should only be 1 because of conduit subs even though there is 2 consumers //for the case where isUseVirtualDestSubsOnCreation is true, @@ -919,9 +941,14 @@ public void testWith2ConsumersRemoveBoth() throws Exception { bridgeConsumer.close(); bridgeConsumer2.close(); - Thread.sleep(2000); + //wait for consumer removal to propagate - demand should be removed + waitForConsumerCount(destinationStatistics, 0); includedProducer.send(test); - Thread.sleep(2000); + + //verify no additional dispatch occurs after consumers removed + final long dispatched = destinationStatistics.getDispatched().getCount(); + assertTrue("should not forward after all consumers removed", + !Wait.waitFor(() -> destinationStatistics.getDispatched().getCount() > dispatched, 2000, 100)); assertLocalBrokerStatistics(destinationStatistics, 1); @@ -949,12 +976,14 @@ public void testExcluded() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(excluded); - Message test = localSession.createTextMessage("test"); - Thread.sleep(1000); + final MessageProducer includedProducer = localSession.createProducer(excluded); + final Message test = localSession.createTextMessage("test"); - MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("exclude.test.bar.bridge")); - Thread.sleep(2000); + final MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("exclude.test.bar.bridge")); + //wait for the remote consumer to be registered on the remote broker + assertTrue("remote consumer not registered", + Wait.waitFor(() -> remoteBroker.getDestination(new ActiveMQQueue("exclude.test.bar.bridge")) + .getConsumers().size() == 1, 10000, 200)); includedProducer.send(test); assertNull(bridgeConsumer.receive(5000)); @@ -990,13 +1019,11 @@ public void testSourceQueue() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeQueue}, true); - MessageProducer includedProducer = localSession.createProducer(new ActiveMQQueue(testQueueName)); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); - + final MessageProducer includedProducer = localSession.createProducer(new ActiveMQQueue(testQueueName)); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(new ActiveMQQueue(testQueueName)).getDestinationStatistics(); - MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("include.test.foo.bridge")); + final MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQQueue("include.test.foo.bridge")); waitForConsumerCount(destinationStatistics, 1); includedProducer.send(test); @@ -1107,7 +1134,8 @@ public void testReplay() throws Exception { localBroker.addNetworkConnector(connector); connector.start(); - Thread.sleep(2000); + //wait for network bridge to be fully started + assertBridgeStarted(); //there should still only be 1 advisory assertRemoteAdvisoryCount(advisoryConsumer, 1); @@ -1177,9 +1205,7 @@ public void testRemovedIfNoConsumer() throws Exception { doSetUp(true, new VirtualDestination[] {compositeTopic}); - MessageConsumer advisoryConsumer = getVirtualDestinationAdvisoryConsumer(testTopicName); - - Thread.sleep(2000); + final MessageConsumer advisoryConsumer = getVirtualDestinationAdvisoryConsumer(testTopicName); //destination creation will trigger the advisory since the virtual topic exists final DestinationStatistics destinationStatistics = @@ -1187,15 +1213,33 @@ public void testRemovedIfNoConsumer() throws Exception { final DestinationStatistics remoteDestStatistics = remoteBroker.getDestination( new ActiveMQQueue("include.test.bar.bridge")).getDestinationStatistics(); - Thread.sleep(2000); - assertAdvisoryBrokerCounts(1,1,1); + //wait for advisory broker to register virtual destination + assertTrue("advisory broker counts not ready", + Wait.waitFor(() -> { + try { + assertAdvisoryBrokerCounts(1,1,1); + return true; + } catch (AssertionError | Exception e) { + return false; + } + }, 10000, 200)); //remove the virtual destinations after startup, will trigger a remove advisory runtimeBroker.setVirtualDestinations(new VirtualDestination[] {}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + //wait for virtual destination removal to propagate + assertTrue("virtual destinations not cleared", + Wait.waitFor(() -> { + try { + assertAdvisoryBrokerCounts(0,0,0); + return true; + } catch (AssertionError | Exception e) { + return false; + } + }, 10000, 200)); + + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); includedProducer.send(test); assertEquals("broker consumer count", 0, destinationStatistics.getConsumers().getCount()); @@ -1226,12 +1270,13 @@ public void testToTopic() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); + //wait for consumer demand to propagate to local broker + final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); + final MessageConsumer bridgeConsumer = remoteSession.createDurableSubscriber(new ActiveMQTopic("include.test.bar.bridge"), "sub1"); + waitForConsumerCount(destinationStatistics, 1); - MessageConsumer bridgeConsumer = remoteSession.createConsumer(new ActiveMQTopic("include.test.bar.bridge")); - Thread.sleep(2000); includedProducer.send(test); assertNotNull(bridgeConsumer.receive(5000)); @@ -1259,9 +1304,20 @@ public void testToTopicNoConsumer() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); + + //wait for virtual destination registration to complete + assertTrue("virtual destination not registered", + Wait.waitFor(() -> { + try { + assertAdvisoryBrokerCounts(1,0,0); + return true; + } catch (AssertionError | Exception e) { + return false; + } + }, 10000, 200)); + includedProducer.send(test); final DestinationStatistics destinationStatistics = localBroker.getDestination(excluded).getDestinationStatistics(); @@ -1289,25 +1345,20 @@ public void testToTopicWithDurable() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); - + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); - MessageConsumer bridgeConsumer = remoteSession.createDurableSubscriber( - new ActiveMQTopic("include.test.bar.bridge"), "sub1"); - Thread.sleep(2000); + final MessageConsumer bridgeConsumer = remoteSession.createDurableSubscriber(new ActiveMQTopic("include.test.bar.bridge"), "sub1"); + //wait for durable subscription demand to propagate + waitForConsumerCount(destinationStatistics, 1); + includedProducer.send(test); assertNotNull(bridgeConsumer.receive(5000)); - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return 1 == destinationStatistics.getDequeues().getCount(); - } - }); + assertTrue("dequeues not updated", + Wait.waitFor(() -> 1 == destinationStatistics.getDequeues().getCount())); assertEquals("broker dest stat dispatched", 1, destinationStatistics.getDispatched().getCount()); assertEquals("broker dest stat dequeues", 1, destinationStatistics.getDequeues().getCount()); @@ -1334,38 +1385,38 @@ public void testToTopicWithDurableOffline() throws Exception { runtimeBroker.setVirtualDestinations(new VirtualDestination[] {compositeTopic}, true); - MessageProducer includedProducer = localSession.createProducer(included); - Thread.sleep(2000); - Message test = localSession.createTextMessage("test"); + final MessageProducer includedProducer = localSession.createProducer(included); + final Message test = localSession.createTextMessage("test"); final DestinationStatistics destinationStatistics = localBroker.getDestination(included).getDestinationStatistics(); //create a durable subscription and go offline - MessageConsumer bridgeConsumer = remoteSession.createDurableSubscriber( + final MessageConsumer bridgeConsumer = remoteSession.createDurableSubscriber( new ActiveMQTopic("include.test.bar.bridge"), "sub1"); + //wait for durable subscription demand to propagate before closing + waitForConsumerCount(destinationStatistics, 1); + bridgeConsumer.close(); - Thread.sleep(2000); + //demand should persist even after durable goes offline includedProducer.send(test); - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return 1 == destinationStatistics.getDequeues().getCount() && - destinationStatistics.getDispatched().getCount() == 1; - } - }); + assertTrue("dequeues and dispatched not updated", + Wait.waitFor(() -> 1 == destinationStatistics.getDequeues().getCount() && + destinationStatistics.getDispatched().getCount() == 1)); //offline durable should still get receive the message over the bridge and ack assertEquals("broker dest stat dispatched", 1, destinationStatistics.getDispatched().getCount()); assertEquals("broker dest stat dequeues", 1, destinationStatistics.getDequeues().getCount()); //reconnect to receive the message - MessageConsumer bridgeConsumer2 = remoteSession.createDurableSubscriber( + final MessageConsumer bridgeConsumer2 = remoteSession.createDurableSubscriber( new ActiveMQTopic("include.test.bar.bridge"), "sub1"); assertNotNull(bridgeConsumer2.receive(5000)); - Thread.sleep(2000); - //make sure stats did not change + //make sure stats did not change - verify no additional dispatches + assertTrue("stats should remain stable after reconnect", + !Wait.waitFor(() -> destinationStatistics.getDispatched().getCount() > 1 + || destinationStatistics.getDequeues().getCount() > 1, 2000, 100)); assertEquals("broker dest stat dispatched", 1, destinationStatistics.getDispatched().getCount()); assertEquals("broker dest stat dequeues", 1, destinationStatistics.getDequeues().getCount()); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTestSupport.java b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTestSupport.java index 6c493fdc298..db8996a9d3f 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTestSupport.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverClusterTestSupport.java @@ -51,6 +51,10 @@ public class FailoverClusterTestSupport extends TestCase { private final Map brokers = new HashMap(); private final List connections = new ArrayList(); + protected List getConnections() { + return connections; + } + protected void assertClientsConnectedToTwoBrokers() throws Exception { assertClientsConnectedToXBrokers(2); } @@ -61,21 +65,16 @@ protected void assertClientsConnectedToThreeBrokers() throws Exception { protected void assertClientsConnectedToXBrokers(final int x) throws Exception { final Set set = new HashSet(); - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { + assertTrue("Only " + x + " connections should be found: " + set, + Wait.waitFor(() -> { set.clear(); - for (ActiveMQConnection c : connections) { + for (final ActiveMQConnection c : connections) { if (c.getTransportChannel().getRemoteAddress() != null) { set.add(c.getTransportChannel().getRemoteAddress()); } } return set.size() == x; - } - }); - - assertTrue("Only " + x + " connections should be found: " + set, - set.size() == x); + })); } protected void assertClientsConnectionsEvenlyDistributed(double minimumPercentage) { @@ -106,31 +105,40 @@ protected void assertClientsConnectionsEvenlyDistributed(double minimumPercentag } protected void assertAllConnected(final int expected) throws Exception { - assertTrue("All connections connected!", Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - int connectedCount = 0; - for (ActiveMQConnection c : connections) { - if(c.getTransportChannel().isConnected()) { - connectedCount++; - } + assertTrue("All connections connected!", Wait.waitFor(() -> { + int connectedCount = 0; + for (final ActiveMQConnection c : connections) { + if (c.getTransportChannel().isConnected()) { + connectedCount++; } - logger.info("Found " + connectedCount + " of " + expected + " connected"); - return connectedCount == expected; } + logger.info("Found " + connectedCount + " of " + expected + " connected"); + return connectedCount == expected; })); } - protected void assertAllConnectedTo(String url) throws Exception { - for (ActiveMQConnection c : connections) { - assertEquals(url, c.getTransportChannel().getRemoteAddress()); - } + protected void assertAllConnectedTo(final String url) throws Exception { + assertTrue("All connections should be connected to " + url, + Wait.waitFor(() -> { + for (final ActiveMQConnection c : connections) { + if (!url.equals(c.getTransportChannel().getRemoteAddress())) { + return false; + } + } + return true; + }, 10000, 100)); } - protected void assertBrokerInfo(String brokerName) throws Exception { - for (ActiveMQConnection c : connections) { - assertEquals(brokerName, c.getBrokerInfo().getBrokerName()); - } + protected void assertBrokerInfo(final String brokerName) throws Exception { + assertTrue("All connections should report broker " + brokerName, + Wait.waitFor(() -> { + for (final ActiveMQConnection c : connections) { + if (c.getBrokerInfo() == null || !brokerName.equals(c.getBrokerInfo().getBrokerName())) { + return false; + } + } + return true; + }, 10000, 100)); } protected void addBroker(String name, BrokerService brokerService) { diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverComplexClusterTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverComplexClusterTest.java index 5b0a9453c0c..729ae98a95b 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverComplexClusterTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverComplexClusterTest.java @@ -16,8 +16,17 @@ */ package org.apache.activemq.transport.failover; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import org.apache.activemq.ActiveMQConnection; +import org.apache.activemq.broker.BrokerService; import org.apache.activemq.broker.PublishedAddressPolicy; import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.Wait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,15 +41,18 @@ public class FailoverComplexClusterTest extends FailoverClusterTestSupport { protected final Logger LOG = LoggerFactory.getLogger(FailoverComplexClusterTest.class); - private static final String BROKER_A_CLIENT_TC_ADDRESS = "tcp://127.0.0.1:61616"; - private static final String BROKER_B_CLIENT_TC_ADDRESS = "tcp://127.0.0.1:61617"; - private static final String BROKER_C_CLIENT_TC_ADDRESS = "tcp://127.0.0.1:61618"; - private static final String BROKER_A_NOB_TC_ADDRESS = "tcp://127.0.0.1:61626"; - private static final String BROKER_B_NOB_TC_ADDRESS = "tcp://127.0.0.1:61627"; - private static final String BROKER_C_NOB_TC_ADDRESS = "tcp://127.0.0.1:61628"; private static final String BROKER_A_NAME = "BROKERA"; private static final String BROKER_B_NAME = "BROKERB"; private static final String BROKER_C_NAME = "BROKERC"; + private static final String EPHEMERAL_BIND_ADDRESS = "tcp://127.0.0.1:0"; + + // Resolved addresses after broker start (set dynamically per test) + private String brokerAClientAddr; + private String brokerBClientAddr; + private String brokerCClientAddr; + private String brokerANobAddr; + private String brokerBNobAddr; + private String brokerCNobAddr; /** * Basic dynamic failover 3 broker test @@ -51,11 +63,8 @@ public void testThreeBrokerClusterSingleConnectorBasic() throws Exception { initSingleTcBroker("", null, null); - Thread.sleep(2000); - - setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + setClientUrl("failover://(" + brokerAClientAddr + "," + brokerBClientAddr + ")"); createClients(); - Thread.sleep(2000); runTests(false, null, null, null); } @@ -72,11 +81,8 @@ public void testThreeBrokerClusterSingleConnectorBackupFailoverConfig() throws E initSingleTcBroker("", null, null); - Thread.sleep(2000); - - setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")?backup=true&backupPoolSize=2&useExponentialBackOff=false&initialReconnectDelay=500"); + setClientUrl("failover://(" + brokerAClientAddr + "," + brokerBClientAddr + ")?backup=true&backupPoolSize=2&useExponentialBackOff=false&initialReconnectDelay=500"); createClients(); - Thread.sleep(2000); runTests(false, null, null, null); } @@ -93,10 +99,8 @@ public void testThreeBrokerClusterSingleConnectorWithParams() throws Exception { initSingleTcBroker("?transport.closeAsync=false", null, null); - Thread.sleep(2000); - setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + setClientUrl("failover://(" + brokerAClientAddr + "," + brokerBClientAddr + ")"); createClients(); - Thread.sleep(2000); runTests(false, null, null, null); } @@ -110,8 +114,7 @@ public void testThreeBrokerClusterWithClusterFilter() throws Exception { initSingleTcBroker("?transport.closeAsync=false", null, null); - Thread.sleep(2000); - setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + setClientUrl("failover://(" + brokerAClientAddr + "," + brokerBClientAddr + ")"); createClients(); runTests(false, null, "*", null); @@ -127,11 +130,8 @@ public void testThreeBrokerClusterMultipleConnectorBasic() throws Exception { initMultiTcCluster("", null); - Thread.sleep(2000); - - setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + setClientUrl("failover://(" + brokerAClientAddr + "," + brokerBClientAddr + ")"); createClients(); - Thread.sleep(2000); runTests(true, null, null, null); } @@ -144,9 +144,7 @@ public void testThreeBrokerClusterMultipleConnectorBasic() throws Exception { public void testOriginalBrokerRestart() throws Exception { initSingleTcBroker("", null, null); - Thread.sleep(2000); - - setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + setClientUrl("failover://(" + brokerAClientAddr + "," + brokerBClientAddr + ")"); createClients(); assertClientsConnectedToThreeBrokers(); @@ -160,6 +158,9 @@ public void testOriginalBrokerRestart() throws Exception { createBrokerA(false, null, null, null); getBroker(BROKER_A_NAME).waitUntilStarted(); + // Wait for bridges from the recreated broker A to form + waitForBridgesFromBroker(BROKER_A_NAME); + assertClientsConnectedToThreeBrokers(); } @@ -173,10 +174,8 @@ public void testThreeBrokerClusterClientDistributions() throws Exception { initSingleTcBroker("", null, null); - Thread.sleep(2000); - setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false&initialReconnectDelay=500&randomize=false"); + setClientUrl("failover://(" + brokerAClientAddr + "," + brokerBClientAddr + ")?useExponentialBackOff=false&initialReconnectDelay=500&randomize=false"); createClients(100); - Thread.sleep(5000); runClientDistributionTests(false, null, null, null); } @@ -191,85 +190,106 @@ public void testThreeBrokerClusterDestinationFilter() throws Exception { initSingleTcBroker("", null, null); - Thread.sleep(2000); - setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")"); + setClientUrl("failover://(" + brokerAClientAddr + "," + brokerBClientAddr + ")"); createClients(); runTests(false, null, null, "Queue.TEST.FOO.>"); } - public void testFailOverWithUpdateClientsOnRemove() throws Exception{ - // Broker A + public void testFailOverWithUpdateClientsOnRemove() throws Exception { + // Broker A - start first with ephemeral port addBroker(BROKER_A_NAME, createBroker(BROKER_A_NAME)); - TransportConnector connectorA = getBroker(BROKER_A_NAME).addConnector(BROKER_A_CLIENT_TC_ADDRESS); + final TransportConnector connectorA = getBroker(BROKER_A_NAME).addConnector(EPHEMERAL_BIND_ADDRESS); connectorA.setName("openwire"); connectorA.setRebalanceClusterClients(true); connectorA.setUpdateClusterClients(true); connectorA.setUpdateClusterClientsOnRemove(true); //If set to false the test succeeds. - addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + BROKER_B_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + connectorA.getPublishedAddressPolicy().setPublishedHostStrategy(PublishedAddressPolicy.PublishedHostStrategy.IPADDRESS); getBroker(BROKER_A_NAME).start(); + getBroker(BROKER_A_NAME).waitUntilStarted(); + brokerAClientAddr = connectorA.getPublishableConnectString(); - // Broker B + // Broker B - start with ephemeral port, bridge to A using resolved address addBroker(BROKER_B_NAME, createBroker(BROKER_B_NAME)); - TransportConnector connectorB = getBroker(BROKER_B_NAME).addConnector(BROKER_B_CLIENT_TC_ADDRESS); + final TransportConnector connectorB = getBroker(BROKER_B_NAME).addConnector(EPHEMERAL_BIND_ADDRESS); connectorB.setName("openwire"); connectorB.setRebalanceClusterClients(true); connectorB.setUpdateClusterClients(true); connectorB.setUpdateClusterClientsOnRemove(true); //If set to false the test succeeds. - addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + BROKER_A_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + connectorB.getPublishedAddressPolicy().setPublishedHostStrategy(PublishedAddressPolicy.PublishedHostStrategy.IPADDRESS); + addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + brokerAClientAddr + ")?useExponentialBackOff=false", false, null); getBroker(BROKER_B_NAME).start(); - getBroker(BROKER_B_NAME).waitUntilStarted(); - Thread.sleep(1000); + brokerBClientAddr = connectorB.getPublishableConnectString(); - // create client connecting only to A. It should receive broker B address whet it connects to A. - setClientUrl("failover:(" + BROKER_A_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=true"); + // Now add A->B bridge using B's resolved address and start it + addAndStartNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + brokerBClientAddr + ")?useExponentialBackOff=false", false, null); + + // Wait for both bridges to form + assertTrue("A->B bridge should form", + Wait.waitFor(() -> !getBroker(BROKER_A_NAME).getNetworkConnectors().get(0).activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(15), TimeUnit.MILLISECONDS.toMillis(500))); + assertTrue("B->A bridge should form", + Wait.waitFor(() -> !getBroker(BROKER_B_NAME).getNetworkConnectors().get(0).activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(15), TimeUnit.MILLISECONDS.toMillis(500))); + + // create client connecting only to A. It should receive broker B address when it connects to A. + setClientUrl("failover:(" + brokerAClientAddr + ")?useExponentialBackOff=true"); createClients(1); - Thread.sleep(5000); + + // Wait for all clients to be connected + assertAllConnected(1); // We stop broker A. - logger.info("Stopping broker A whose address is: {}", BROKER_A_CLIENT_TC_ADDRESS); + logger.info("Stopping broker A whose address is: {}", brokerAClientAddr); getBroker(BROKER_A_NAME).stop(); getBroker(BROKER_A_NAME).waitUntilStopped(); - Thread.sleep(5000); - // Client should failover to B. - assertAllConnectedTo(BROKER_B_CLIENT_TC_ADDRESS); + // Client should failover to B - wait for it + assertAllConnectedTo(brokerBClientAddr); } public void testStaticInfoAvailableAfterPattialUpdate() throws Exception { addBroker(BROKER_A_NAME, createBroker(BROKER_A_NAME)); - TransportConnector connectorA = getBroker(BROKER_A_NAME).addConnector(BROKER_A_CLIENT_TC_ADDRESS); + final TransportConnector connectorA = getBroker(BROKER_A_NAME).addConnector(EPHEMERAL_BIND_ADDRESS); connectorA.setName("openwire"); connectorA.setRebalanceClusterClients(true); connectorA.setUpdateClusterClients(true); connectorA.getPublishedAddressPolicy().setPublishedHostStrategy(PublishedAddressPolicy.PublishedHostStrategy.IPADDRESS); getBroker(BROKER_A_NAME).start(); + getBroker(BROKER_A_NAME).waitUntilStarted(); + brokerAClientAddr = connectorA.getPublishableConnectString(); + + // Reserve a port for broker B by using a temporary ServerSocket + final int brokerBPort; + try (final ServerSocket ss = new ServerSocket(0, 1, InetAddress.getByName("127.0.0.1"))) { + brokerBPort = ss.getLocalPort(); + } + final String brokerBBindAddr = "tcp://127.0.0.1:" + brokerBPort; - setClientUrl("failover://(" + BROKER_A_CLIENT_TC_ADDRESS + "?trace=true," + BROKER_B_CLIENT_TC_ADDRESS + "?trace=true)?useExponentialBackOff=false&initialReconnectDelay=500"); + setClientUrl("failover://(" + brokerAClientAddr + "?trace=true," + brokerBBindAddr + "?trace=true)?useExponentialBackOff=false&initialReconnectDelay=500"); createClients(1); - assertAllConnectedTo(BROKER_A_CLIENT_TC_ADDRESS); + assertAllConnectedTo(brokerAClientAddr); getBroker(BROKER_A_NAME).stop(); + getBroker(BROKER_A_NAME).waitUntilStopped(); - + // Now start broker B on the reserved port addBroker(BROKER_B_NAME, createBroker(BROKER_B_NAME)); - TransportConnector connectorB = getBroker(BROKER_B_NAME).addConnector(BROKER_B_CLIENT_TC_ADDRESS); + final TransportConnector connectorB = getBroker(BROKER_B_NAME).addConnector(brokerBBindAddr); connectorB.setName("openwire"); connectorB.setRebalanceClusterClients(true); connectorB.setUpdateClusterClients(true); connectorB.getPublishedAddressPolicy().setPublishedHostStrategy(PublishedAddressPolicy.PublishedHostStrategy.IPADDRESS); getBroker(BROKER_B_NAME).start(); - getBroker(BROKER_B_NAME).waitUntilStarted(); - Thread.sleep(1000); - // verify can connect? - assertAllConnectedTo(BROKER_B_CLIENT_TC_ADDRESS); + // verify client connects to B + assertAllConnectedTo(brokerBBindAddr); } /** @@ -288,7 +308,7 @@ public void testStaticInfoAvailableAfterPattialUpdate() throws Exception { * @throws Exception * @throws InterruptedException */ - private void runTests(boolean multi, String tcParams, String clusterFilter, String destinationFilter) throws Exception, InterruptedException { + private void runTests(final boolean multi, final String tcParams, final String clusterFilter, final String destinationFilter) throws Exception, InterruptedException { assertClientsConnectedToThreeBrokers(); LOG.info("Stopping BrokerC in prep for restart"); @@ -302,6 +322,9 @@ private void runTests(boolean multi, String tcParams, String clusterFilter, Stri createBrokerC(multi, tcParams, clusterFilter, destinationFilter); getBroker(BROKER_C_NAME).waitUntilStarted(); + // Wait for network bridges from the recreated broker C to form + waitForBridgesFromBroker(BROKER_C_NAME); + assertClientsConnectedToThreeBrokers(); } @@ -313,7 +336,7 @@ private void runTests(boolean multi, String tcParams, String clusterFilter, Stri * @throws Exception * @throws InterruptedException */ - private void runClientDistributionTests(boolean multi, String tcParams, String clusterFilter, String destinationFilter) throws Exception, InterruptedException { + private void runClientDistributionTests(final boolean multi, final String tcParams, final String clusterFilter, final String destinationFilter) throws Exception, InterruptedException { assertClientsConnectedToThreeBrokers(); assertClientsConnectionsEvenlyDistributed(.25); @@ -327,6 +350,9 @@ private void runClientDistributionTests(boolean multi, String tcParams, String c createBrokerC(multi, tcParams, clusterFilter, destinationFilter); getBroker(BROKER_C_NAME).waitUntilStarted(); + // Wait for network bridges from the recreated broker C to form + waitForBridgesFromBroker(BROKER_C_NAME); + assertClientsConnectedToThreeBrokers(); assertClientsConnectionsEvenlyDistributed(.20); } @@ -338,72 +364,201 @@ protected void setUp() throws Exception { @Override protected void tearDown() throws Exception { shutdownClients(); - Thread.sleep(2000); destroyBrokerCluster(); } - private void initSingleTcBroker(String params, String clusterFilter, String destinationFilter) throws Exception { - createBrokerA(false, params, clusterFilter, null); - createBrokerB(false, params, clusterFilter, null); - createBrokerC(false, params, clusterFilter, null); + private void initSingleTcBroker(final String params, final String clusterFilter, final String destinationFilter) throws Exception { + final String tcParams = (params == null) ? "" : params; + + // Phase 1: Create and start all 3 brokers with transport connectors only + addBroker(BROKER_A_NAME, createBroker(BROKER_A_NAME)); + addTransportConnector(getBroker(BROKER_A_NAME), "openwire", EPHEMERAL_BIND_ADDRESS + tcParams, true); + getBroker(BROKER_A_NAME).start(); + getBroker(BROKER_A_NAME).waitUntilStarted(); + brokerAClientAddr = getBroker(BROKER_A_NAME).getTransportConnectors().get(0).getPublishableConnectString(); + + addBroker(BROKER_B_NAME, createBroker(BROKER_B_NAME)); + addTransportConnector(getBroker(BROKER_B_NAME), "openwire", EPHEMERAL_BIND_ADDRESS + tcParams, true); + getBroker(BROKER_B_NAME).start(); + getBroker(BROKER_B_NAME).waitUntilStarted(); + brokerBClientAddr = getBroker(BROKER_B_NAME).getTransportConnectors().get(0).getPublishableConnectString(); + + addBroker(BROKER_C_NAME, createBroker(BROKER_C_NAME)); + addTransportConnector(getBroker(BROKER_C_NAME), "openwire", EPHEMERAL_BIND_ADDRESS + tcParams, true); + getBroker(BROKER_C_NAME).start(); getBroker(BROKER_C_NAME).waitUntilStarted(); + brokerCClientAddr = getBroker(BROKER_C_NAME).getTransportConnectors().get(0).getPublishableConnectString(); + + // Phase 2: Add network bridges using resolved addresses and start them + addAndStartNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + brokerBClientAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_A_NAME), "A_2_C_Bridge", "static://(" + brokerCClientAddr + ")?useExponentialBackOff=false", false, null); + + addAndStartNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + brokerAClientAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_B_NAME), "B_2_C_Bridge", "static://(" + brokerCClientAddr + ")?useExponentialBackOff=false", false, null); + + addAndStartNetworkBridge(getBroker(BROKER_C_NAME), "C_2_A_Bridge", "static://(" + brokerAClientAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_C_NAME), "C_2_B_Bridge", "static://(" + brokerBClientAddr + ")?useExponentialBackOff=false", false, null); + + // Wait for all bridges to form + waitForAllBridges(); } - private void initMultiTcCluster(String params, String clusterFilter) throws Exception { - createBrokerA(true, params, clusterFilter, null); - createBrokerB(true, params, clusterFilter, null); - createBrokerC(true, params, clusterFilter, null); + private void initMultiTcCluster(final String params, final String clusterFilter) throws Exception { + final String tcParams = (params == null) ? "" : params; + + // Phase 1: Create and start all 3 brokers with both transport connectors + addBroker(BROKER_A_NAME, createBroker(BROKER_A_NAME)); + addTransportConnector(getBroker(BROKER_A_NAME), "openwire", EPHEMERAL_BIND_ADDRESS + tcParams, true); + addTransportConnector(getBroker(BROKER_A_NAME), "network", EPHEMERAL_BIND_ADDRESS + tcParams, false); + getBroker(BROKER_A_NAME).start(); + getBroker(BROKER_A_NAME).waitUntilStarted(); + brokerAClientAddr = getBroker(BROKER_A_NAME).getTransportConnectorByName("openwire").getPublishableConnectString(); + brokerANobAddr = getBroker(BROKER_A_NAME).getTransportConnectorByName("network").getPublishableConnectString(); + + addBroker(BROKER_B_NAME, createBroker(BROKER_B_NAME)); + addTransportConnector(getBroker(BROKER_B_NAME), "openwire", EPHEMERAL_BIND_ADDRESS + tcParams, true); + addTransportConnector(getBroker(BROKER_B_NAME), "network", EPHEMERAL_BIND_ADDRESS + tcParams, false); + getBroker(BROKER_B_NAME).start(); + getBroker(BROKER_B_NAME).waitUntilStarted(); + brokerBClientAddr = getBroker(BROKER_B_NAME).getTransportConnectorByName("openwire").getPublishableConnectString(); + brokerBNobAddr = getBroker(BROKER_B_NAME).getTransportConnectorByName("network").getPublishableConnectString(); + + addBroker(BROKER_C_NAME, createBroker(BROKER_C_NAME)); + addTransportConnector(getBroker(BROKER_C_NAME), "openwire", EPHEMERAL_BIND_ADDRESS + tcParams, true); + addTransportConnector(getBroker(BROKER_C_NAME), "network", EPHEMERAL_BIND_ADDRESS + tcParams, false); + getBroker(BROKER_C_NAME).start(); getBroker(BROKER_C_NAME).waitUntilStarted(); + brokerCClientAddr = getBroker(BROKER_C_NAME).getTransportConnectorByName("openwire").getPublishableConnectString(); + brokerCNobAddr = getBroker(BROKER_C_NAME).getTransportConnectorByName("network").getPublishableConnectString(); + + // Phase 2: Add network bridges using network connector addresses and start them + addAndStartNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + brokerBNobAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_A_NAME), "A_2_C_Bridge", "static://(" + brokerCNobAddr + ")?useExponentialBackOff=false", false, null); + + addAndStartNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + brokerANobAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_B_NAME), "B_2_C_Bridge", "static://(" + brokerCNobAddr + ")?useExponentialBackOff=false", false, null); + + addAndStartNetworkBridge(getBroker(BROKER_C_NAME), "C_2_A_Bridge", "static://(" + brokerANobAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_C_NAME), "C_2_B_Bridge", "static://(" + brokerBNobAddr + ")?useExponentialBackOff=false", false, null); + + // Wait for all bridges to form + waitForAllBridges(); } - private void createBrokerA(boolean multi, String params, String clusterFilter, String destinationFilter) throws Exception { - final String tcParams = (params == null)?"":params; + /** + * Creates broker A with transport connector and network bridges to B and C. + * Rebinds to the same port that was previously used (stored in brokerAClientAddr). + * Used for re-creating broker A after it has been stopped. + */ + private void createBrokerA(final boolean multi, final String params, final String clusterFilter, final String destinationFilter) throws Exception { + final String tcParams = (params == null) ? "" : params; if (getBroker(BROKER_A_NAME) == null) { + final String bindAddr = extractBindAddress(brokerAClientAddr); + addBroker(BROKER_A_NAME, createBroker(BROKER_A_NAME)); - addTransportConnector(getBroker(BROKER_A_NAME), "openwire", BROKER_A_CLIENT_TC_ADDRESS + tcParams, true); if (multi) { - addTransportConnector(getBroker(BROKER_A_NAME), "network", BROKER_A_NOB_TC_ADDRESS + tcParams, false); - addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + BROKER_B_NOB_TC_ADDRESS + ")?useExponentialBackOff=false", false, clusterFilter); - addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_C_Bridge", "static://(" + BROKER_C_NOB_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + final String nobBindAddr = extractBindAddress(brokerANobAddr); + addTransportConnector(getBroker(BROKER_A_NAME), "openwire", bindAddr + tcParams, true); + addTransportConnector(getBroker(BROKER_A_NAME), "network", nobBindAddr + tcParams, false); } else { - addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + BROKER_B_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, clusterFilter); - addNetworkBridge(getBroker(BROKER_A_NAME), "A_2_C_Bridge", "static://(" + BROKER_C_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + addTransportConnector(getBroker(BROKER_A_NAME), "openwire", bindAddr + tcParams, true); } getBroker(BROKER_A_NAME).start(); - } - } - - private void createBrokerB(boolean multi, String params, String clusterFilter, String destinationFilter) throws Exception { - final String tcParams = (params == null)?"":params; - if (getBroker(BROKER_B_NAME) == null) { - addBroker(BROKER_B_NAME, createBroker(BROKER_B_NAME)); - addTransportConnector(getBroker(BROKER_B_NAME), "openwire", BROKER_B_CLIENT_TC_ADDRESS + tcParams, true); + getBroker(BROKER_A_NAME).waitUntilStarted(); + brokerAClientAddr = getBroker(BROKER_A_NAME).getTransportConnectorByName("openwire").getPublishableConnectString(); if (multi) { - addTransportConnector(getBroker(BROKER_B_NAME), "network", BROKER_B_NOB_TC_ADDRESS + tcParams, false); - addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + BROKER_A_NOB_TC_ADDRESS + ")?useExponentialBackOff=false", false, clusterFilter); - addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_C_Bridge", "static://(" + BROKER_C_NOB_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + brokerANobAddr = getBroker(BROKER_A_NAME).getTransportConnectorByName("network").getPublishableConnectString(); + addAndStartNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + brokerBNobAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_A_NAME), "A_2_C_Bridge", "static://(" + brokerCNobAddr + ")?useExponentialBackOff=false", false, null); } else { - addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_A_Bridge", "static://(" + BROKER_A_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, clusterFilter); - addNetworkBridge(getBroker(BROKER_B_NAME), "B_2_C_Bridge", "static://(" + BROKER_C_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + addAndStartNetworkBridge(getBroker(BROKER_A_NAME), "A_2_B_Bridge", "static://(" + brokerBClientAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_A_NAME), "A_2_C_Bridge", "static://(" + brokerCClientAddr + ")?useExponentialBackOff=false", false, null); } - getBroker(BROKER_B_NAME).start(); } } - private void createBrokerC(boolean multi, String params, String clusterFilter, String destinationFilter) throws Exception { - final String tcParams = (params == null)?"":params; + /** + * Creates broker C with transport connector and network bridges to A and B. + * Rebinds to the same port that was previously used (stored in brokerCClientAddr). + * Used for re-creating broker C after it has been stopped. + */ + private void createBrokerC(final boolean multi, final String params, final String clusterFilter, final String destinationFilter) throws Exception { + final String tcParams = (params == null) ? "" : params; if (getBroker(BROKER_C_NAME) == null) { + final String bindAddr = extractBindAddress(brokerCClientAddr); + addBroker(BROKER_C_NAME, createBroker(BROKER_C_NAME)); - addTransportConnector(getBroker(BROKER_C_NAME), "openwire", BROKER_C_CLIENT_TC_ADDRESS + tcParams, true); if (multi) { - addTransportConnector(getBroker(BROKER_C_NAME), "network", BROKER_C_NOB_TC_ADDRESS + tcParams, false); - addNetworkBridge(getBroker(BROKER_C_NAME), "C_2_A_Bridge", "static://(" + BROKER_A_NOB_TC_ADDRESS + ")?useExponentialBackOff=false", false, clusterFilter); - addNetworkBridge(getBroker(BROKER_C_NAME), "C_2_B_Bridge", "static://(" + BROKER_B_NOB_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + final String nobBindAddr = extractBindAddress(brokerCNobAddr); + addTransportConnector(getBroker(BROKER_C_NAME), "openwire", bindAddr + tcParams, true); + addTransportConnector(getBroker(BROKER_C_NAME), "network", nobBindAddr + tcParams, false); } else { - addNetworkBridge(getBroker(BROKER_C_NAME), "C_2_A_Bridge", "static://(" + BROKER_A_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, clusterFilter); - addNetworkBridge(getBroker(BROKER_C_NAME), "C_2_B_Bridge", "static://(" + BROKER_B_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); + addTransportConnector(getBroker(BROKER_C_NAME), "openwire", bindAddr + tcParams, true); } getBroker(BROKER_C_NAME).start(); + getBroker(BROKER_C_NAME).waitUntilStarted(); + brokerCClientAddr = getBroker(BROKER_C_NAME).getTransportConnectorByName("openwire").getPublishableConnectString(); + if (multi) { + brokerCNobAddr = getBroker(BROKER_C_NAME).getTransportConnectorByName("network").getPublishableConnectString(); + addAndStartNetworkBridge(getBroker(BROKER_C_NAME), "C_2_A_Bridge", "static://(" + brokerANobAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_C_NAME), "C_2_B_Bridge", "static://(" + brokerBNobAddr + ")?useExponentialBackOff=false", false, null); + } else { + addAndStartNetworkBridge(getBroker(BROKER_C_NAME), "C_2_A_Bridge", "static://(" + brokerAClientAddr + ")?useExponentialBackOff=false", false, clusterFilter); + addAndStartNetworkBridge(getBroker(BROKER_C_NAME), "C_2_B_Bridge", "static://(" + brokerBClientAddr + ")?useExponentialBackOff=false", false, null); + } + } + } + + /** + * Extracts the bind address (tcp://host:port) from a publishable connect string. + */ + private static String extractBindAddress(final String publishableAddr) throws Exception { + final URI uri = new URI(publishableAddr); + return "tcp://127.0.0.1:" + uri.getPort(); + } + + /** + * Adds a network bridge to a broker and starts it immediately. + * This is used when the broker is already running. + */ + private void addAndStartNetworkBridge(final BrokerService broker, final String bridgeName, + final String uri, final boolean duplex, final String destinationFilter) throws Exception { + final NetworkConnector network = broker.addNetworkConnector(uri); + network.setName(bridgeName); + network.setDuplex(duplex); + if (destinationFilter != null && !destinationFilter.isEmpty()) { + network.setDestinationFilter(destinationFilter); + } + broker.startNetworkConnector(network, null); + } + + /** + * Waits for all network bridges on all brokers to become active. + */ + private void waitForAllBridges() throws Exception { + for (final String brokerName : new String[]{BROKER_A_NAME, BROKER_B_NAME, BROKER_C_NAME}) { + final BrokerService broker = getBroker(brokerName); + if (broker != null) { + for (final NetworkConnector nc : broker.getNetworkConnectors()) { + assertTrue("bridge " + nc.getName() + " on " + brokerName + " should form", + Wait.waitFor(() -> !nc.activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(15), TimeUnit.MILLISECONDS.toMillis(500))); + } + } + } + } + + /** + * Waits for network bridges FROM the specified broker to become active. + */ + private void waitForBridgesFromBroker(final String brokerName) throws Exception { + final BrokerService broker = getBroker(brokerName); + if (broker != null) { + for (final NetworkConnector nc : broker.getNetworkConnectors()) { + assertTrue("bridge " + nc.getName() + " on " + brokerName + " should form", + Wait.waitFor(() -> !nc.activeBridges().isEmpty(), + TimeUnit.SECONDS.toMillis(15), TimeUnit.MILLISECONDS.toMillis(500))); + } } } } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverPriorityTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverPriorityTest.java index 72137dd110d..03b492f4ab3 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverPriorityTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverPriorityTest.java @@ -28,7 +28,11 @@ public class FailoverPriorityTest extends FailoverClusterTestSupport { private static final String BROKER_A_CLIENT_TC_ADDRESS = "tcp://127.0.0.1:61616"; private static final String BROKER_B_CLIENT_TC_ADDRESS = "tcp://127.0.0.1:61617"; private static final String BROKER_C_CLIENT_TC_ADDRESS = "tcp://127.0.0.1:61618"; - private final HashMap urls = new HashMap(); + private final HashMap urls = new HashMap<>(); + + private static final String BROKER_A_NAME = "BROKERA"; + private static final String BROKER_B_NAME = "BROKERB"; + private static final String BROKER_C_NAME = "BROKERC"; @Override public void setUp() throws Exception { @@ -37,16 +41,10 @@ public void setUp() throws Exception { urls.put(BROKER_B_NAME, BROKER_B_CLIENT_TC_ADDRESS); } - private static final String BROKER_A_NAME = "BROKERA"; - private static final String BROKER_B_NAME = "BROKERB"; - private static final String BROKER_C_NAME = "BROKERC"; - - public void testPriorityBackup() throws Exception { createBrokerA(); createBrokerB(); getBroker(BROKER_B_NAME).waitUntilStarted(); - Thread.sleep(1000); setClientUrl("failover:(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")?randomize=false&priorityBackup=true&initialReconnectDelay=1000&useExponentialBackOff=false"); createClients(5); @@ -60,23 +58,17 @@ public void testPriorityBackup() throws Exception { restart(true, BROKER_A_NAME, BROKER_B_NAME); } - Thread.sleep(5000); - restart(false, BROKER_A_NAME, BROKER_B_NAME); - } public void testPriorityBackupList() throws Exception { createBrokerA(); createBrokerB(); getBroker(BROKER_B_NAME).waitUntilStarted(); - Thread.sleep(1000); setClientUrl("failover:(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")?randomize=false&priorityBackup=true&priorityURIs=tcp://127.0.0.1:61617&initialReconnectDelay=1000&useExponentialBackOff=false"); createClients(5); - Thread.sleep(3000); - assertAllConnectedTo(urls.get(BROKER_B_NAME)); restart(false, BROKER_B_NAME, BROKER_A_NAME); @@ -86,7 +78,6 @@ public void testPriorityBackupList() throws Exception { } restart(false, BROKER_B_NAME, BROKER_A_NAME); - } public void testThreeBrokers() throws Exception { @@ -111,9 +102,7 @@ public void testThreeBrokers() throws Exception { addNetworkBridge(getBroker(BROKER_C_NAME), "C_2_B_Bridge", "static://(" + BROKER_B_CLIENT_TC_ADDRESS + ")?useExponentialBackOff=false", false, null); getBroker(BROKER_C_NAME).start(); - getBroker(BROKER_C_NAME).waitUntilStarted(); - Thread.sleep(1000); setClientUrl("failover:(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + "," + BROKER_C_CLIENT_TC_ADDRESS + ")?randomize=false&priorityBackup=true&initialReconnectDelay=1000&useExponentialBackOff=false"); @@ -122,7 +111,6 @@ public void testThreeBrokers() throws Exception { assertAllConnectedTo(urls.get(BROKER_A_NAME)); restart(true, BROKER_A_NAME, BROKER_B_NAME); - } public void testPriorityBackupAndUpdateClients() throws Exception { @@ -139,7 +127,6 @@ public void testPriorityBackupAndUpdateClients() throws Exception { getBroker(BROKER_B_NAME).start(); getBroker(BROKER_B_NAME).waitUntilStarted(); - Thread.sleep(1000); setClientUrl("failover:(" + BROKER_A_CLIENT_TC_ADDRESS + "," + BROKER_B_CLIENT_TC_ADDRESS + ")?randomize=false&priorityBackup=true&initialReconnectDelay=1000&useExponentialBackOff=false"); @@ -147,52 +134,28 @@ public void testPriorityBackupAndUpdateClients() throws Exception { createClients(5); - // Let's wait a little bit longer just in case it takes a while to realize that the - // Broker A is the one with higher priority. - Thread.sleep(5000); - assertAllConnectedTo(urls.get(BROKER_A_NAME)); } - private void restart(boolean primary, String primaryName, String secondaryName) throws Exception { - - Thread.sleep(1000); - - if (primary) { - LOG.info("Stopping " + primaryName); - stopBroker(primaryName); - } else { - LOG.info("Stopping " + secondaryName); - stopBroker(secondaryName); - } - Thread.sleep(5000); + private void restart(final boolean primary, final String primaryName, final String secondaryName) throws Exception { + final String stoppingName = primary ? primaryName : secondaryName; + final String remainingName = primary ? secondaryName : primaryName; - if (primary) { - assertAllConnectedTo(urls.get(secondaryName)); - assertBrokerInfo(secondaryName); - } else { - assertAllConnectedTo(urls.get(primaryName)); - assertBrokerInfo(primaryName); - } + LOG.info("Stopping " + stoppingName); + stopBroker(stoppingName); - if (primary) { - LOG.info("Starting " + primaryName); - createBrokerByName(primaryName); - getBroker(primaryName).waitUntilStarted(); - } else { - LOG.info("Starting " + secondaryName); - createBrokerByName(secondaryName); - getBroker(secondaryName).waitUntilStarted(); - } + assertAllConnectedTo(urls.get(remainingName)); + assertBrokerInfo(remainingName); - Thread.sleep(5000); + LOG.info("Starting " + stoppingName); + createBrokerByName(stoppingName); + getBroker(stoppingName).waitUntilStarted(); assertAllConnectedTo(urls.get(primaryName)); assertBrokerInfo(primaryName); - } - private void createBrokerByName(String name) throws Exception { + private void createBrokerByName(final String name) throws Exception { if (name.equals(BROKER_A_NAME)) { createBrokerA(); } else if (name.equals(BROKER_B_NAME)) { diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUpdateURIsTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUpdateURIsTest.java index 16740891ee7..c0afc530aa2 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUpdateURIsTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/failover/FailoverUpdateURIsTest.java @@ -18,7 +18,6 @@ import java.io.File; import java.io.FileOutputStream; -import java.util.concurrent.TimeUnit; import jakarta.jms.Connection; import jakarta.jms.Message; @@ -33,6 +32,7 @@ import org.apache.activemq.broker.BrokerService; import org.apache.activemq.broker.TransportConnector; import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.Wait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,8 +41,6 @@ public class FailoverUpdateURIsTest extends TestCase { private static final String QUEUE_NAME = "test.failoverupdateuris"; private static final Logger LOG = LoggerFactory.getLogger(FailoverUpdateURIsTest.class); - String firstTcpUri = "tcp://localhost:61616"; - String secondTcpUri = "tcp://localhost:61626"; Connection connection = null; BrokerService bs1 = null; BrokerService bs2 = null; @@ -62,28 +60,31 @@ public void tearDown() throws Exception { public void testUpdateURIsViaFile() throws Exception { - String targetDir = "target/" + getName(); + final String targetDir = "target/" + getName(); new File(targetDir).mkdir(); - File updateFile = new File(targetDir + "/updateURIsFile.txt"); + final File updateFile = new File(targetDir + "/updateURIsFile.txt"); LOG.info("updateFile:" + updateFile); LOG.info("updateFileUri:" + updateFile.toURI()); LOG.info("updateFileAbsoluteFile:" + updateFile.getAbsoluteFile()); LOG.info("updateFileAbsoluteFileUri:" + updateFile.getAbsoluteFile().toURI()); + + bs1 = createBroker("bs1", "tcp://localhost:0"); + bs1.start(); + bs1.waitUntilStarted(); + final String firstTcpUri = bs1.getTransportConnectors().get(0).getConnectUri().toString(); + FileOutputStream out = new FileOutputStream(updateFile); out.write(firstTcpUri.getBytes()); out.close(); - bs1 = createBroker("bs1", firstTcpUri); - bs1.start(); - // no failover uri's to start with, must be read from file... - ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:()?updateURIsURL=file:///" + updateFile.getAbsoluteFile()); + final ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:()?updateURIsURL=file:///" + updateFile.getAbsoluteFile()); connection = cf.createConnection(); connection.start(); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue theQueue = session.createQueue(QUEUE_NAME); - MessageProducer producer = session.createProducer(theQueue); - MessageConsumer consumer = session.createConsumer(theQueue); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue theQueue = session.createQueue(QUEUE_NAME); + final MessageProducer producer = session.createProducer(theQueue); + final MessageConsumer consumer = session.createConsumer(theQueue); Message message = session.createTextMessage("Test message"); producer.send(message); Message msg = consumer.receive(2000); @@ -93,13 +94,15 @@ public void testUpdateURIsViaFile() throws Exception { bs1.waitUntilStopped(); bs1 = null; - bs2 = createBroker("bs2", secondTcpUri); + bs2 = createBroker("bs2", "tcp://localhost:0"); bs2.start(); + bs2.waitUntilStarted(); + final String secondTcpUri = bs2.getTransportConnectors().get(0).getConnectUri().toString(); // add the transport uri for broker number 2 out = new FileOutputStream(updateFile, true); out.write(",".getBytes()); - out.write(secondTcpUri.toString().getBytes()); + out.write(secondTcpUri.getBytes()); out.close(); producer.send(message); @@ -107,8 +110,8 @@ public void testUpdateURIsViaFile() throws Exception { assertNotNull(msg); } - private BrokerService createBroker(String name, String tcpUri) throws Exception { - BrokerService bs = new BrokerService(); + private BrokerService createBroker(final String name, final String tcpUri) throws Exception { + final BrokerService bs = new BrokerService(); bs.setBrokerName(name); bs.setUseJmx(false); bs.setPersistent(false); @@ -120,30 +123,33 @@ public void testAutoUpdateURIs() throws Exception { bs1 = new BrokerService(); bs1.setUseJmx(false); - TransportConnector transportConnector = bs1.addConnector(firstTcpUri); + final TransportConnector transportConnector = bs1.addConnector("tcp://localhost:0"); transportConnector.setUpdateClusterClients(true); bs1.start(); + bs1.waitUntilStarted(); + final String firstTcpUri = bs1.getTransportConnectors().get(0).getConnectUri().toString(); - ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + firstTcpUri + ")"); + final ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("failover:(" + firstTcpUri + ")"); connection = cf.createConnection(); connection.start(); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue theQueue = session.createQueue(QUEUE_NAME); - MessageProducer producer = session.createProducer(theQueue); - MessageConsumer consumer = session.createConsumer(theQueue); - Message message = session.createTextMessage("Test message"); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue theQueue = session.createQueue(QUEUE_NAME); + final MessageProducer producer = session.createProducer(theQueue); + final MessageConsumer consumer = session.createConsumer(theQueue); + final Message message = session.createTextMessage("Test message"); producer.send(message); Message msg = consumer.receive(4000); assertNotNull(msg); - bs2 = createBroker("bs2", secondTcpUri); - NetworkConnector networkConnector = bs2.addNetworkConnector("static:(" + firstTcpUri + ")"); + bs2 = createBroker("bs2", "tcp://localhost:0"); + final NetworkConnector networkConnector = bs2.addNetworkConnector("static:(" + firstTcpUri + ")"); networkConnector.setDuplex(true); bs2.start(); LOG.info("started brokerService 2"); bs2.waitUntilStarted(); - TimeUnit.SECONDS.sleep(4); + assertTrue("bs2 bridge started in time", Wait.waitFor(() -> + !bs2.getNetworkConnectors().get(0).activeBridges().isEmpty(), 10000, 200)); LOG.info("stopping brokerService 1"); bs1.stop(); diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTest.java index f0697f58d7a..e4d9f73fc05 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTest.java @@ -18,7 +18,6 @@ package org.apache.activemq.transport.fanout; import jakarta.jms.Connection; -import jakarta.jms.Message; import jakarta.jms.MessageConsumer; import jakarta.jms.MessageProducer; import jakarta.jms.Session; @@ -26,7 +25,6 @@ import junit.framework.TestCase; import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.broker.BrokerFactory; import org.apache.activemq.broker.BrokerService; import org.apache.activemq.util.MessageIdList; @@ -34,64 +32,77 @@ public class FanoutTest extends TestCase { BrokerService broker1; BrokerService broker2; - - ActiveMQConnectionFactory producerFactory = new ActiveMQConnectionFactory("fanout:(static:(tcp://localhost:61616,tcp://localhost:61617))?fanOutQueues=true"); + Connection producerConnection; Session producerSession; - int messageCount = 100; + final int messageCount = 100; public void setUp() throws Exception { - broker1 = BrokerFactory.createBroker("broker:(tcp://localhost:61616)/brokerA?persistent=false&useJmx=false"); - broker2 = BrokerFactory.createBroker("broker:(tcp://localhost:61617)/brokerB?persistent=false&useJmx=false"); - + broker1 = new BrokerService(); + broker1.setBrokerName("brokerA"); + broker1.setPersistent(false); + broker1.setUseJmx(false); + broker1.addConnector("tcp://localhost:0"); broker1.start(); - broker2.start(); - broker1.waitUntilStarted(); + + broker2 = new BrokerService(); + broker2.setBrokerName("brokerB"); + broker2.setPersistent(false); + broker2.setUseJmx(false); + broker2.addConnector("tcp://localhost:0"); + broker2.start(); broker2.waitUntilStarted(); - + + final String broker1Uri = broker1.getTransportConnectors().get(0).getConnectUri().toString(); + final String broker2Uri = broker2.getTransportConnectors().get(0).getConnectUri().toString(); + + final ActiveMQConnectionFactory producerFactory = new ActiveMQConnectionFactory( + "fanout:(static:(" + broker1Uri + "," + broker2Uri + "))?fanOutQueues=true"); producerConnection = producerFactory.createConnection(); producerConnection.start(); producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); } - + public void tearDown() throws Exception { producerSession.close(); producerConnection.close(); - + broker1.stop(); broker2.stop(); } - + public void testSendReceive() throws Exception { - MessageProducer prod = createProducer(); + final MessageProducer prod = createProducer(); for (int i = 0; i < messageCount; i++) { - Message msg = producerSession.createTextMessage("Message " + i); - prod.send(msg); + prod.send(producerSession.createTextMessage("Message " + i)); } prod.close(); - - assertMessagesReceived("tcp://localhost:61616"); - assertMessagesReceived("tcp://localhost:61617"); - + + final String broker1Uri = broker1.getTransportConnectors().get(0).getConnectUri().toString(); + final String broker2Uri = broker2.getTransportConnectors().get(0).getConnectUri().toString(); + assertMessagesReceived(broker1Uri); + assertMessagesReceived(broker2Uri); } - + protected MessageProducer createProducer() throws Exception { - return producerSession.createProducer(producerSession.createQueue("TEST")); + return producerSession.createProducer(producerSession.createQueue("TEST")); } - - protected void assertMessagesReceived(String brokerURL) throws Exception { - ActiveMQConnectionFactory consumerFactory = new ActiveMQConnectionFactory(brokerURL); - Connection consumerConnection = consumerFactory.createConnection(); + + protected void assertMessagesReceived(final String brokerURL) throws Exception { + final ActiveMQConnectionFactory consumerFactory = new ActiveMQConnectionFactory(brokerURL); + final Connection consumerConnection = consumerFactory.createConnection(); consumerConnection.start(); - Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = consumerSession.createConsumer(consumerSession.createQueue("TEST")); - MessageIdList listener = new MessageIdList(); + final Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = consumerSession.createConsumer(consumerSession.createQueue("TEST")); + final MessageIdList listener = new MessageIdList(); consumer.setMessageListener(listener); listener.waitForMessagesToArrive(messageCount); listener.assertMessagesReceived(messageCount); - - consumer.close(); consumerConnection.close(); consumerSession.close(); + + consumer.close(); + consumerConnection.close(); + consumerSession.close(); } } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTransportBrokerTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTransportBrokerTest.java index e384d7a34a7..8c40eb30a5d 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTransportBrokerTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/transport/fanout/FanoutTransportBrokerTest.java @@ -63,29 +63,29 @@ public void initCombosForTestPublisherFansout() { public void testPublisherFansout() throws Exception { // Start a normal consumer on the local broker - StubConnection connection1 = createConnection(); - ConnectionInfo connectionInfo1 = createConnectionInfo(); - SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); - ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + final StubConnection connection1 = createConnection(); + final ConnectionInfo connectionInfo1 = createConnectionInfo(); + final SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + final ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); connection1.send(connectionInfo1); connection1.send(sessionInfo1); connection1.request(consumerInfo1); // Start a normal consumer on a remote broker - StubConnection connection2 = createRemoteConnection(); - ConnectionInfo connectionInfo2 = createConnectionInfo(); - SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); - ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + final StubConnection connection2 = createRemoteConnection(); + final ConnectionInfo connectionInfo2 = createConnectionInfo(); + final SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + final ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); connection2.send(connectionInfo2); connection2.send(sessionInfo2); connection2.request(consumerInfo2); // Start a fanout publisher. LOG.info("Starting the fanout connection."); - StubConnection connection3 = createFanoutConnection(); - ConnectionInfo connectionInfo3 = createConnectionInfo(); - SessionInfo sessionInfo3 = createSessionInfo(connectionInfo3); - ProducerInfo producerInfo3 = createProducerInfo(sessionInfo3); + final StubConnection connection3 = createFanoutConnection(); + final ConnectionInfo connectionInfo3 = createConnectionInfo(); + final SessionInfo sessionInfo3 = createSessionInfo(connectionInfo3); + final ProducerInfo producerInfo3 = createProducerInfo(sessionInfo3); connection3.send(connectionInfo3); connection3.send(sessionInfo3); connection3.send(producerInfo3); @@ -109,19 +109,19 @@ public void initCombosForTestPublisherWaitsForServerToBeUp() { public void testPublisherWaitsForServerToBeUp() throws Exception { // Start a normal consumer on the local broker - StubConnection connection1 = createConnection(); - ConnectionInfo connectionInfo1 = createConnectionInfo(); - SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); - ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); + final StubConnection connection1 = createConnection(); + final ConnectionInfo connectionInfo1 = createConnectionInfo(); + final SessionInfo sessionInfo1 = createSessionInfo(connectionInfo1); + final ConsumerInfo consumerInfo1 = createConsumerInfo(sessionInfo1, destination); connection1.send(connectionInfo1); connection1.send(sessionInfo1); connection1.request(consumerInfo1); // Start a normal consumer on a remote broker - StubConnection connection2 = createRemoteConnection(); - ConnectionInfo connectionInfo2 = createConnectionInfo(); - SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); - ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); + final StubConnection connection2 = createRemoteConnection(); + final ConnectionInfo connectionInfo2 = createConnectionInfo(); + final SessionInfo sessionInfo2 = createSessionInfo(connectionInfo2); + final ConsumerInfo consumerInfo2 = createConsumerInfo(sessionInfo2, destination); connection2.send(connectionInfo2); connection2.send(sessionInfo2); connection2.request(consumerInfo2); @@ -129,8 +129,8 @@ public void testPublisherWaitsForServerToBeUp() throws Exception { // Start a fanout publisher. LOG.info("Starting the fanout connection."); final StubConnection connection3 = createFanoutConnection(); - ConnectionInfo connectionInfo3 = createConnectionInfo(); - SessionInfo sessionInfo3 = createSessionInfo(connectionInfo3); + final ConnectionInfo connectionInfo3 = createConnectionInfo(); + final SessionInfo sessionInfo3 = createSessionInfo(connectionInfo3); final ProducerInfo producerInfo3 = createProducerInfo(sessionInfo3); connection3.send(connectionInfo3); connection3.send(sessionInfo3); @@ -149,7 +149,7 @@ public void testPublisherWaitsForServerToBeUp() throws Exception { // The MockTransport is on the remote connection. // Slip in a new transport filter after the MockTransport - MockTransport mt = (MockTransport)connection3.getTransport().narrow(MockTransport.class); + final MockTransport mt = (MockTransport)connection3.getTransport().narrow(MockTransport.class); mt.install(new TransportFilter(mt.getNext()) { public void oneway(Object command) throws IOException { LOG.info("Dropping: " + command); @@ -185,17 +185,17 @@ public void run() { } protected String getLocalURI() { - return "tcp://localhost:61616"; + return "tcp://localhost:0"; } protected String getRemoteURI() { - return "tcp://localhost:61617"; + return "tcp://localhost:0"; } protected StubConnection createFanoutConnection() throws Exception { - URI fanoutURI = new URI("fanout://(static://(" + connector.getServer().getConnectURI() + "," + "mock://" + remoteConnector.getServer().getConnectURI() + "))?fanOutQueues=true"); - Transport transport = TransportFactory.connect(fanoutURI); - StubConnection connection = new StubConnection(transport); + final URI fanoutURI = new URI("fanout://(static://(" + connector.getServer().getConnectURI() + "," + "mock://" + remoteConnector.getServer().getConnectURI() + "))?fanOutQueues=true"); + final Transport transport = TransportFactory.connect(fanoutURI); + final StubConnection connection = new StubConnection(transport); connections.add(connection); return connection; } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/ClientRebalanceTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/ClientRebalanceTest.java index c20243a6db4..47b867457aa 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/ClientRebalanceTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/ClientRebalanceTest.java @@ -18,6 +18,10 @@ import static org.junit.Assert.assertNotEquals; +import java.net.URI; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + import jakarta.jms.Connection; import jakarta.jms.Message; import jakarta.jms.MessageConsumer; @@ -27,127 +31,247 @@ import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.JmsMultipleBrokersTestSupport; -import org.apache.activemq.broker.TransportConnection; +import org.apache.activemq.broker.BrokerService; import org.apache.activemq.broker.TransportConnector; +import org.apache.activemq.broker.TransportConnection; import org.apache.activemq.command.ConnectionControl; +import org.apache.activemq.network.DiscoveryNetworkConnector; +import org.apache.activemq.network.NetworkBridge; +import org.apache.activemq.network.NetworkConnector; +import org.apache.activemq.util.Wait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; public class ClientRebalanceTest extends JmsMultipleBrokersTestSupport { private static final Logger LOG = LoggerFactory.getLogger(ClientRebalanceTest.class); private static final String QUEUE_NAME = "Test.ClientRebalanceTest"; + private static final AtomicInteger BROKER_SEQUENCE = new AtomicInteger(0); protected void setUp() throws Exception { setAutoFail(true); super.setUp(); } - public void testRebalance() throws Exception { - createBroker(new ClassPathResource("org/apache/activemq/usecases/rebalance-broker1.xml")); - createBroker(new ClassPathResource("org/apache/activemq/usecases/rebalance-broker2.xml")); + // Use unique broker names to avoid VM transport registry collisions between tests + final String b1Name = "rb1-" + BROKER_SEQUENCE.incrementAndGet(); + final String b2Name = "rb2-" + BROKER_SEQUENCE.incrementAndGet(); + final String b3Name = "rb3-" + BROKER_SEQUENCE.incrementAndGet(); + + final BrokerService b1 = createBrokerProgrammatically(b1Name); + final BrokerService b2 = createBrokerProgrammatically(b2Name); - startAllBrokers(); + // Start b1 and b2 first to get their assigned ports + b1.start(); + b1.waitUntilStarted(); + b2.start(); + b2.waitUntilStarted(); - brokers.get("b1").broker.waitUntilStarted(); + final URI b1Uri = getConnectUri(b1); + final URI b2Uri = getConnectUri(b2); + + // Wire network connectors between b1 and b2 + final NetworkConnector nc_b1_b2 = addAndStartNetworkConnector(b1, b1Name + "_" + b2Name, b2Uri); + final NetworkConnector nc_b2_b1 = addAndStartNetworkConnector(b2, b2Name + "_" + b1Name, b1Uri); + + // Wait for bridges to form between b1 and b2 + waitForBridgeOnConnector(nc_b1_b2, b1Name + "->" + b2Name); + waitForBridgeOnConnector(nc_b2_b1, b2Name + "->" + b1Name); LOG.info("Starting connection"); - ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("failover:(tcp://localhost:61616,tcp://localhost:61617)?randomize=false"); - Connection conn = factory.createConnection(); + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + "failover:(" + b1Uri + "," + b2Uri + ")?randomize=false"); + final Connection conn = factory.createConnection(); conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue theQueue = session.createQueue(QUEUE_NAME); - MessageProducer producer = session.createProducer(theQueue); - MessageConsumer consumer = session.createConsumer(theQueue); - Message message = session.createTextMessage("Test message"); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue theQueue = session.createQueue(QUEUE_NAME); + final MessageProducer producer = session.createProducer(theQueue); + final MessageConsumer consumer = session.createConsumer(theQueue); + final Message message = session.createTextMessage("Test message"); producer.send(message); - Message msg = consumer.receive(2000); + final Message msg = consumer.receive(5000); assertNotNull(msg); - // introduce third broker - createBroker(new ClassPathResource("org/apache/activemq/usecases/rebalance-broker3.xml")); - brokers.get("b3").broker.waitUntilStarted(); - - Thread.sleep(3000); + // Introduce third broker + final BrokerService b3 = createBrokerProgrammatically(b3Name); + b3.setUseJmx(true); + b3.start(); + b3.waitUntilStarted(); + + final URI b3Uri = getConnectUri(b3); + + // Wire network connectors for b3 + final NetworkConnector nc_b1_b3 = addAndStartNetworkConnector(b1, b1Name + "_" + b3Name, b3Uri); + addAndStartNetworkConnector(b2, b2Name + "_" + b3Name, b3Uri); + final NetworkConnector nc_b3_b1 = addAndStartNetworkConnector(b3, b3Name + "_" + b1Name, b1Uri); + addAndStartNetworkConnector(b3, b3Name + "_" + b2Name, b2Uri); + + // Wait for bridges involving b3 to form + waitForBridgeOnConnector(nc_b1_b3, b1Name + "->" + b3Name); + waitForBridgeOnConnector(nc_b3_b1, b3Name + "->" + b1Name); LOG.info("Stopping broker 1"); - brokers.get("b1").broker.stop(); - brokers.get("b1").broker.waitUntilStopped(); - - Thread.sleep(3000); - // should reconnect to some of the remaining brokers - producer.send(message); - msg = consumer.receive(2000); - assertNotNull(msg); + b1.stop(); + b1.waitUntilStopped(); + brokers.remove(b1Name); + + // Wait for failover reconnect: the client should reconnect to b2 or b3 + // Verify by successfully sending and receiving a message + assertTrue("should be able to send/receive after b1 stop", + Wait.waitFor(() -> { + try { + producer.send(message); + final Message received = consumer.receive(2000); + return received != null; + } catch (final Exception e) { + return false; + } + }, TimeUnit.SECONDS.toMillis(15), TimeUnit.MILLISECONDS.toMillis(500))); LOG.info("Stopping broker 2"); - brokers.get("b2").broker.stop(); - brokers.get("b2").broker.waitUntilStopped(); + b2.stop(); + b2.waitUntilStopped(); + brokers.remove(b2Name); - // should reconnect to broker3 - producer.send(message); - msg = consumer.receive(2000); - assertNotNull(msg); + // Should reconnect to broker3 + assertTrue("should be able to send/receive after b2 stop", + Wait.waitFor(() -> { + try { + producer.send(message); + final Message received = consumer.receive(2000); + return received != null; + } catch (final Exception e) { + return false; + } + }, TimeUnit.SECONDS.toMillis(15), TimeUnit.MILLISECONDS.toMillis(500))); } - + public void testReconnect() throws Exception { - createBroker(new ClassPathResource("org/apache/activemq/usecases/rebalance-broker1.xml")); - createBroker(new ClassPathResource("org/apache/activemq/usecases/rebalance-broker2.xml")); + // Use unique broker names to avoid VM transport registry collisions between tests + final String b1Name = "rc1-" + BROKER_SEQUENCE.incrementAndGet(); + final String b2Name = "rc2-" + BROKER_SEQUENCE.incrementAndGet(); + + final BrokerService b1 = createBrokerProgrammatically(b1Name); + final BrokerService b2 = createBrokerProgrammatically(b2Name); - startAllBrokers(); + b1.start(); + b1.waitUntilStarted(); + b2.start(); + b2.waitUntilStarted(); - brokers.get("b1").broker.waitUntilStarted(); + final URI b1Uri = getConnectUri(b1); + final URI b2Uri = getConnectUri(b2); + + // Wire network connectors between b1 and b2 + final NetworkConnector nc_b1_b2 = addAndStartNetworkConnector(b1, b1Name + "_" + b2Name, b2Uri); + addAndStartNetworkConnector(b2, b2Name + "_" + b1Name, b1Uri); + + // Wait for bridge to form + waitForBridgeOnConnector(nc_b1_b2, b1Name + "->" + b2Name); LOG.info("Starting connection"); - ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("failover:(tcp://localhost:61616)?randomize=false"); - Connection conn = factory.createConnection(); + final ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory( + "failover:(" + b1Uri + ")?randomize=false"); + final Connection conn = factory.createConnection(); conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue theQueue = session.createQueue("Test.ClientReconnectTest"); - MessageProducer producer = session.createProducer(theQueue); - MessageConsumer consumer = session.createConsumer(theQueue); - Message message = session.createTextMessage("Test message"); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue theQueue = session.createQueue("Test.ClientReconnectTest"); + final MessageProducer producer = session.createProducer(theQueue); + final MessageConsumer consumer = session.createConsumer(theQueue); + final Message message = session.createTextMessage("Test message"); producer.send(message); - Message msg = consumer.receive(2000); + final Message msg = consumer.receive(5000); assertNotNull(msg); - TransportConnector transportConnector = brokers.get("b1").broker.getTransportConnectorByName("openwire"); + final TransportConnector transportConnector = b1.getTransportConnectorByName("openwire"); assertNotNull(transportConnector); - TransportConnection startFailoverConnection = findClientFailoverTransportConnection(transportConnector); - + final TransportConnection startFailoverConnection = findClientFailoverTransportConnection(transportConnector); assertNotNull(startFailoverConnection); - String startConnectionId = startFailoverConnection.getConnectionId(); - String startRemoteAddress = startFailoverConnection.getRemoteAddress(); - ConnectionControl simulateRebalance = new ConnectionControl(); - simulateRebalance.setReconnectTo("tcp://localhost:61616"); + + final String startConnectionId = startFailoverConnection.getConnectionId(); + final String startRemoteAddress = startFailoverConnection.getRemoteAddress(); + final ConnectionControl simulateRebalance = new ConnectionControl(); + simulateRebalance.setReconnectTo(b1Uri.toString()); startFailoverConnection.dispatchSync(simulateRebalance); - Thread.sleep(2000l); + // Wait for the failover reconnection to complete + assertTrue("client should reconnect with different remote address", + Wait.waitFor(() -> { + final TransportConnection afterConnection = findClientFailoverTransportConnection(transportConnector); + return afterConnection != null + && startConnectionId.equals(afterConnection.getConnectionId()) + && !startRemoteAddress.equals(afterConnection.getRemoteAddress()); + }, TimeUnit.SECONDS.toMillis(10), TimeUnit.MILLISECONDS.toMillis(200))); - TransportConnection afterFailoverConnection = findClientFailoverTransportConnection(transportConnector); + final TransportConnection afterFailoverConnection = findClientFailoverTransportConnection(transportConnector); assertNotNull(afterFailoverConnection); assertEquals(startConnectionId, afterFailoverConnection.getConnectionId()); assertNotEquals(startRemoteAddress, afterFailoverConnection.getRemoteAddress()); - // should still be able to send without exception to broker3 + + // Should still be able to send without exception producer.send(message); - msg = consumer.receive(2000); - assertNotNull(msg); + final Message receivedMsg = consumer.receive(5000); + assertNotNull(receivedMsg); conn.close(); } - - protected TransportConnection findClientFailoverTransportConnection(TransportConnector transportConnector) { + + private BrokerService createBrokerProgrammatically(final String brokerName) throws Exception { + final BrokerService broker = new BrokerService(); + broker.setBrokerName(brokerName); + broker.setPersistent(false); + broker.setUseJmx(false); + + final TransportConnector tc = broker.addConnector("tcp://localhost:0"); + tc.setName("openwire"); + tc.setRebalanceClusterClients(true); + tc.setUpdateClusterClients(true); + + brokers.put(brokerName, new BrokerItem(broker)); + return broker; + } + + /** + * Get the connect URI for a broker's openwire transport connector. + */ + private URI getConnectUri(final BrokerService broker) throws Exception { + return broker.getTransportConnectorByName("openwire").getConnectUri(); + } + + private NetworkConnector addAndStartNetworkConnector(final BrokerService broker, final String name, final URI remoteUri) throws Exception { + final DiscoveryNetworkConnector nc = new DiscoveryNetworkConnector( + new URI("static:(" + remoteUri + ")?useExponentialBackOff=false")); + nc.setName(name); + nc.setDuplex(false); + broker.addNetworkConnector(nc); + broker.startNetworkConnector(nc, null); + return nc; + } + + private void waitForBridgeOnConnector(final NetworkConnector connector, final String description) throws Exception { + assertTrue(description + " bridge should form", + Wait.waitFor(() -> { + for (final NetworkBridge bridge : connector.activeBridges()) { + if (bridge.getRemoteBrokerName() != null) { + LOG.info("Bridge formed: {} -> {}", description, bridge.getRemoteBrokerName()); + return true; + } + } + return false; + }, TimeUnit.SECONDS.toMillis(30), TimeUnit.MILLISECONDS.toMillis(200))); + } + + protected TransportConnection findClientFailoverTransportConnection(final TransportConnector transportConnector) { TransportConnection failoverConnection = null; - for(TransportConnection tmpConnection : transportConnector.getConnections()) { - if(tmpConnection.isNetworkConnection()) { + for (final TransportConnection tmpConnection : transportConnector.getConnections()) { + if (tmpConnection.isNetworkConnection()) { continue; } - if(tmpConnection.isFaultTolerantConnection()) { + if (tmpConnection.isFaultTolerantConnection()) { failoverConnection = tmpConnection; } } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableRedeliveryTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableRedeliveryTest.java index 6d7c5e3ce23..bdfca6f630a 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableRedeliveryTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableRedeliveryTest.java @@ -52,9 +52,9 @@ @Category(ParallelTest.class) public class DurableRedeliveryTest { - static final Logger LOG = LoggerFactory.getLogger(DurableRedeliveryTest.class); - BrokerService broker = null; - String topicName = "testTopic"; + private static final Logger LOG = LoggerFactory.getLogger(DurableRedeliveryTest.class); + private BrokerService broker = null; + private final String topicName = "testTopic"; @Before public void setUp() throws Exception { @@ -68,9 +68,9 @@ public void tearDown() throws Exception { broker.stop(); } - protected void configureBroker(BrokerService broker) throws Exception { - PolicyMap policyMap = new PolicyMap(); - PolicyEntry policy = new PolicyEntry(); + protected void configureBroker(final BrokerService broker) throws Exception { + final PolicyMap policyMap = new PolicyMap(); + final PolicyEntry policy = new PolicyEntry(); policyMap.setDefaultEntry(policy); broker.setDestinationPolicy(policyMap); broker.setPersistent(false); @@ -80,29 +80,33 @@ protected void configureBroker(BrokerService broker) throws Exception { @Test public void testRedeliveryFlagAfterConnectionKill() throws Exception { - ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( + final ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( broker.getTransportConnectors().get(0).getPublishableConnectString()); - ActiveMQConnection producerConnection = (ActiveMQConnection) connectionFactory.createConnection(); + final ActiveMQConnection producerConnection = (ActiveMQConnection) connectionFactory.createConnection(); ActiveMQConnection durableConnection = (ActiveMQConnection) connectionFactory.createConnection(); durableConnection.setClientID("clientId"); producerConnection.start(); durableConnection.start(); Session session = durableConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = session.createTopic(topicName); + final Topic topic = session.createTopic(topicName); MessageConsumer consumer = session.createDurableSubscriber(topic, "sub1"); populateDestination(1, topic, producerConnection); producerConnection.close(); - Wait.waitFor(() -> broker.getBroker().getClients().length == 1); + assertTrue("only durable client remains", + Wait.waitFor(() -> broker.getBroker().getClients().length == 1)); //Close the connection on the broker side (not the client) so the delivered status of the //prefetched message will be unknown which should now trigger the previously dispatched message //to be marked as redelivered - TransportConnector connector = broker.getTransportConnectors().get(0); - TransportConnection connection = connector.getConnections().stream().findFirst().get(); + final TransportConnector connector = broker.getTransportConnectors().get(0); + assertTrue("only durable connection remains", + Wait.waitFor(() -> connector.getConnections().size() == 1)); + final TransportConnection connection = connector.getConnections().stream().findFirst().get(); connection.stop(); - Wait.waitFor(() -> broker.getBroker().getClients().length == 0); + assertTrue("all clients disconnected", + Wait.waitFor(() -> broker.getBroker().getClients().length == 0)); //Reconnect and consume the message durableConnection = (ActiveMQConnection) connectionFactory.createConnection(); @@ -110,21 +114,19 @@ public void testRedeliveryFlagAfterConnectionKill() throws Exception { durableConnection.start(); session = durableConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - topic = session.createTopic(topicName); - consumer = session.createDurableSubscriber(topic, "sub1"); + consumer = session.createDurableSubscriber(session.createTopic(topicName), "sub1"); - Message msg = consumer.receive(2000); + final Message msg = consumer.receive(2000); LOG.info("got: " + msg); assertNotNull("got the message", msg); assertTrue("got the message has redelivered flag", msg.getJMSRedelivered()); - producerConnection.close(); durableConnection.close(); } - private void populateDestination(final int nbMessages, final Destination destination, jakarta.jms.Connection connection) throws JMSException { - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = session.createProducer(destination); + private void populateDestination(final int nbMessages, final Destination destination, final jakarta.jms.Connection connection) throws JMSException { + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageProducer producer = session.createProducer(destination); for (int i = 1; i <= nbMessages; i++) { producer.send(session.createTextMessage("test: " + i)); } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOfflineTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOfflineTest.java index 5ca3797ff37..d0f1624c5f8 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOfflineTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionOfflineTest.java @@ -43,6 +43,7 @@ import java.util.concurrent.TimeUnit; 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; @@ -56,7 +57,7 @@ public class DurableSubscriptionOfflineTest extends DurableSubscriptionOfflineTe @Override protected ActiveMQConnectionFactory createConnectionFactory() throws Exception { - ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + getName(true)); + final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://" + getName(true)); connectionFactory.setWatchTopicAdvisories(false); return connectionFactory; } @@ -75,15 +76,15 @@ public void testConsumeAllMatchedMessages() throws Exception { session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); - int sent = 0; - for (int i = 0; i < 10; i++) { - sent++; - Message message = session.createMessage(); + final int sent = 10; + for (int i = 0; i < sent; i++) { + final Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); } - Thread.sleep(1 * 1000); + assertTrue("messages enqueued to topic", + Wait.waitFor(() -> broker.getDestination(topic).getDestinationStatistics().getEnqueues().getCount() >= 10, 5000, 100)); session.close(); con.close(); @@ -91,11 +92,12 @@ public void testConsumeAllMatchedMessages() throws Exception { // consume messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); - DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + final MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + final DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); - Thread.sleep(3 * 1000); + assertTrue("all messages received by listener", + Wait.waitFor(() -> listener.count >= sent, 5000, 100)); session.close(); con.close(); @@ -115,30 +117,31 @@ public void testBrowseOfflineSub() throws Exception { // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = session.createProducer(null); + final MessageProducer producer = session.createProducer(null); for (int i = 0; i < 10; i++) { - Message message = session.createMessage(); + final Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); } - Thread.sleep(1 * 1000); + assertTrue("messages enqueued to topic", + Wait.waitFor(() -> broker.getDestination(topic).getDestinationStatistics().getEnqueues().getCount() >= 10, 5000, 100)); session.close(); con.close(); // browse the durable sub - ObjectName[] subs = broker.getAdminView().getInactiveDurableTopicSubscribers(); + final ObjectName[] subs = broker.getAdminView().getInactiveDurableTopicSubscribers(); assertEquals(1, subs.length); - ObjectName subName = subs[0]; - DurableSubscriptionViewMBean sub = (DurableSubscriptionViewMBean) + final ObjectName subName = subs[0]; + final DurableSubscriptionViewMBean sub = (DurableSubscriptionViewMBean) broker.getManagementContext().newProxyInstance(subName, DurableSubscriptionViewMBean.class, true); - CompositeData[] data = sub.browse(); + final CompositeData[] data = sub.browse(); assertNotNull(data); assertEquals(10, data.length); - TabularData tabularData = sub.browseAsTable(); + final TabularData tabularData = sub.browseAsTable(); assertNotNull(tabularData); assertEquals(10, tabularData.size()); @@ -154,31 +157,32 @@ public void testTwoOfflineSubscriptionCanConsume() throws Exception { con.close(); // create durable subscription 2 - Connection con2 = createConnection("cliId2"); - Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer2 = session2.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); - DurableSubscriptionOfflineTestListener listener2 = new DurableSubscriptionOfflineTestListener(); + final Connection con2 = createConnection("cliId2"); + final Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer2 = session2.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + final DurableSubscriptionOfflineTestListener listener2 = new DurableSubscriptionOfflineTestListener(); consumer2.setMessageListener(listener2); // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = session.createProducer(null); + final MessageProducer producer = session.createProducer(null); - int sent = 0; - for (int i = 0; i < 10; i++) { - sent++; - Message message = session.createMessage(); + final int sent = 10; + for (int i = 0; i < sent; i++) { + final Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); } - Thread.sleep(1 * 1000); + assertTrue("messages enqueued to topic", + Wait.waitFor(() -> broker.getDestination(topic).getDestinationStatistics().getEnqueues().getCount() >= sent, 5000, 100)); session.close(); con.close(); // test online subs - Thread.sleep(3 * 1000); + assertTrue("online subscriber got all messages", + Wait.waitFor(() -> listener2.count >= sent, 5000, 100)); session2.close(); con2.close(); @@ -187,11 +191,12 @@ public void testTwoOfflineSubscriptionCanConsume() throws Exception { // consume messages con = createConnection("cliId1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); - DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + final MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + final DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); - Thread.sleep(3 * 1000); + assertTrue("all messages received by listener", + Wait.waitFor(() -> listener.count >= sent, 5000, 100)); session.close(); con.close(); @@ -201,7 +206,7 @@ public void testTwoOfflineSubscriptionCanConsume() throws Exception { @Test(timeout = 60 * 1000) public void testRemovedDurableSubDeletes() throws Exception { - String filter = "$a='A1' AND (($b=true AND $c=true) OR ($d='D1' OR $d='D2'))"; + final String filter = "$a='A1' AND (($b=true AND $c=true) OR ($d='D1' OR $d='D2'))"; // create durable subscription 1 Connection con = createConnection("cliId1"); Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); @@ -212,18 +217,19 @@ public void testRemovedDurableSubDeletes() throws Exception { // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = session.createProducer(null); + final MessageProducer producer = session.createProducer(null); for (int i = 0; i < 10; i++) { - Message message = session.createMessage(); + final Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); } - Thread.sleep(1 * 1000); + assertTrue("messages enqueued to topic", + Wait.waitFor(() -> broker.getDestination(topic).getDestinationStatistics().getEnqueues().getCount() >= 10, 5000, 100)); - Connection con2 = createConnection("cliId1"); - Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Connection con2 = createConnection("cliId1"); + final Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); session2.unsubscribe("SubsId"); session2.close(); con2.close(); @@ -232,8 +238,8 @@ public void testRemovedDurableSubDeletes() throws Exception { topic = new ActiveMQTopic(topic.getPhysicalName() + "?consumer.retroactive=true"); con = createConnection("offCli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); - DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + final MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); + final DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); session.close(); con.close(); @@ -249,8 +255,8 @@ public void testRemovedDurableSubDeletesFromIndex() throws Exception { final int numMessages = 2750; - KahaDBPersistenceAdapter kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter)broker.getPersistenceAdapter(); - PageFile pageFile = kahaDBPersistenceAdapter.getStore().getPageFile(); + final KahaDBPersistenceAdapter kahaDBPersistenceAdapter = (KahaDBPersistenceAdapter)broker.getPersistenceAdapter(); + final PageFile pageFile = kahaDBPersistenceAdapter.getStore().getPageFile(); LOG.info("PageCount " + pageFile.getPageCount() + " f:" + pageFile.getFreePageCount() + ", fileSize:" + pageFile.getFile().length()); long lastDiff = 0; @@ -267,17 +273,17 @@ public void testRemovedDurableSubDeletesFromIndex() throws Exception { // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = session.createProducer(null); + final MessageProducer producer = session.createProducer(null); for (int i = 0; i < numMessages; i++) { - Message message = session.createMessage(); + final Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); } con.close(); - Connection con2 = createConnection("cliId1" + "-" + repeats); - Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Connection con2 = createConnection("cliId1" + "-" + repeats); + final Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); session2.unsubscribe("SubsId"); session2.close(); con2.close(); @@ -310,23 +316,22 @@ public void testInterleavedOfflineSubscriptionCanConsumeAfterUnsub() throws Exce // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = session.createProducer(null); + final MessageProducer producer = session.createProducer(null); - int sent = 0; - for (int i = 0; i < 10; i++) { - boolean filter = (int) (Math.random() * 2) >= 1; - - sent++; + final int sent = 10; + for (int i = 0; i < sent; i++) { + final boolean filter = (int) (Math.random() * 2) >= 1; - Message message = session.createMessage(); + final Message message = session.createMessage(); message.setStringProperty("filter", filter ? "true" : "false"); producer.send(topic, message); } - Thread.sleep(1 * 1000); + assertTrue("messages enqueued to topic", + Wait.waitFor(() -> broker.getDestination(topic).getDestinationStatistics().getEnqueues().getCount() >= sent, 5000, 100)); - Connection con2 = createConnection("offCli1"); - Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Connection con2 = createConnection("offCli1"); + final Session session2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); session2.unsubscribe("SubsId"); session2.close(); con2.close(); @@ -334,11 +339,12 @@ public void testInterleavedOfflineSubscriptionCanConsumeAfterUnsub() throws Exce // consume all messages con = createConnection("offCli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); - DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener("SubsId"); + final MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); + final DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener("SubsId"); consumer.setMessageListener(listener); - Thread.sleep(3 * 1000); + assertTrue("offline consumer got all messages", + Wait.waitFor(() -> listener.count >= sent, 5000, 100)); session.close(); con.close(); @@ -361,7 +367,7 @@ public void testNoDuplicateOnConcurrentSendTranCommitAndActivate() throws Except } class CheckForDupsClient implements Runnable { - HashSet ids = new HashSet(); + final HashSet ids = new HashSet(); final int id; public CheckForDupsClient(int id) { @@ -371,24 +377,24 @@ public CheckForDupsClient(int id) { @Override public void run() { try { - Connection con = createConnection("cli" + id); - Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Connection con = createConnection("cli" + id); + final Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); for (int j=0;j<2;j++) { - MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); + final MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); for (int i = 0; i < messageCount/2; i++) { - Message message = consumer.receive(4000); + final Message message = consumer.receive(4000); assertNotNull(message); - long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); + final long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); assertTrue("ID=" + id + " not a duplicate: " + producerSequenceId, ids.add(producerSequenceId)); } consumer.close(); } // verify no duplicates left - MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); - Message message = consumer.receive(4000); + final MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); + final Message message = consumer.receive(4000); if (message != null) { - long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); + final long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); assertTrue("ID=" + id + " not a duplicate: " + producerSequenceId, ids.add(producerSequenceId)); } assertNull(message); @@ -406,23 +412,20 @@ public void run() { final String payLoad = new String(new byte[1000]); con = createConnection(); final Session sendSession = con.createSession(true, Session.SESSION_TRANSACTED); - MessageProducer producer = sendSession.createProducer(topic); + final MessageProducer producer = sendSession.createProducer(topic); for (int i = 0; i < messageCount; i++) { producer.send(sendSession.createTextMessage(payLoad)); } - ExecutorService executorService = Executors.newCachedThreadPool(); + final ExecutorService executorService = Executors.newCachedThreadPool(); // concurrent commit and activate - executorService.execute(new Runnable() { - @Override - public void run() { - try { - sendSession.commit(); - } catch (JMSException e) { - e.printStackTrace(); - exceptions.add(e); - } + executorService.execute(() -> { + try { + sendSession.commit(); + } catch (JMSException e) { + e.printStackTrace(); + exceptions.add(e); } }); for (int i = 0; i < numConsumers; i++) { @@ -484,21 +487,21 @@ public CheckOrderClient(int id) { public void run() { try { synchronized (this) { - Connection con = clientFactory.createConnection(); + final Connection con = clientFactory.createConnection(); con.setClientID("cli" + id); con.start(); - Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); + final Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", null, true); int nextId = 0; ++runCount; int i=0; for (; i < messageCount/2; i++) { - Message message = consumer.receiveNoWait(); + final Message message = consumer.receiveNoWait(); if (message == null) { break; } - long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); + final long producerSequenceId = new MessageId(message.getJMSMessageID()).getProducerSequenceId(); assertEquals(id + " expected order: runCount: " + runCount + " id: " + message.getJMSMessageID(), ++nextId, producerSequenceId); } LOG.info(con.getClientID() + " peeked " + i); @@ -512,15 +515,15 @@ public void run() { } } - Runnable producer = new Runnable() { + final Runnable producerRunnable = new Runnable() { final String payLoad = new String(new byte[600]); @Override public void run() { try { - Connection con = createConnection(); + final Connection con = createConnection(); final Session sendSession = con.createSession(true, Session.SESSION_TRANSACTED); - MessageProducer producer = sendSession.createProducer(topic); + final MessageProducer producer = sendSession.createProducer(topic); for (int i = 0; i < messageCount; i++) { producer.send(sendSession.createTextMessage(payLoad)); } @@ -535,7 +538,7 @@ public void run() { } }; - ExecutorService executorService = Executors.newCachedThreadPool(); + final ExecutorService executorService = Executors.newCachedThreadPool(); // concurrent commit and activate for (int i = 0; i < numConsumers; i++) { @@ -544,7 +547,7 @@ public void run() { executorService.execute(client); } } - executorService.execute(producer); + executorService.execute(producerRunnable); executorService.shutdown(); executorService.awaitTermination(5, TimeUnit.MINUTES); @@ -565,21 +568,22 @@ public void testUnmatchedSubUnsubscribeDeletesAll() throws Exception { // send messages con = createConnection(); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = session.createProducer(null); + final MessageProducer producer = session.createProducer(null); int filtered = 0; for (int i = 0; i < 10; i++) { - boolean filter = (i %2 == 0); //(int) (Math.random() * 2) >= 1; + final boolean filter = (i %2 == 0); //(int) (Math.random() * 2) >= 1; if (filter) filtered++; - Message message = session.createMessage(); + final Message message = session.createMessage(); message.setStringProperty("filter", filter ? "true" : "false"); producer.send(topic, message); } LOG.info("sent: " + filtered); - Thread.sleep(1 * 1000); + assertTrue("messages enqueued to topic", + Wait.waitFor(() -> broker.getDestination(topic).getDestinationStatistics().getEnqueues().getCount() >= 10, 5000, 100)); session.close(); con.close(); @@ -592,11 +596,13 @@ public void testUnmatchedSubUnsubscribeDeletesAll() throws Exception { con = createConnection("offCli1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); - DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); + final MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", "filter = 'true'", true); + final DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); consumer.setMessageListener(listener); - Thread.sleep(3 * 1000); + // After unsubscribe and re-subscribe, no old messages should arrive + assertFalse("no messages should be received after unsubscribe", + Wait.waitFor(() -> listener.count > 0, 3000, 100)); session.close(); con.close(); @@ -624,29 +630,30 @@ public void testAllConsumed() throws Exception { session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); - int sent = 0; - for (int i = 0; i < 10; i++) { - Message message = session.createMessage(); + final int sent = 10; + for (int i = 0; i < sent; i++) { + final Message message = session.createMessage(); message.setStringProperty("filter", "true"); producer.send(topic, message); - sent++; } LOG.info("sent: " + sent); - Thread.sleep(1 * 1000); + assertTrue("messages enqueued to topic", + Wait.waitFor(() -> broker.getDestination(topic).getDestinationStatistics().getEnqueues().getCount() >= sent, 5000, 100)); session.close(); con.close(); con = createConnection("cli1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); - DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener(); - consumer.setMessageListener(listener); - Thread.sleep(3 * 1000); + final DurableSubscriptionOfflineTestListener listener1 = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener1); + assertTrue("cli1 got all messages", + Wait.waitFor(() -> listener1.count >= sent, 5000, 100)); session.close(); con.close(); - assertEquals(sent, listener.count); + assertEquals(sent, listener1.count); LOG.info("cli2 pull 2"); con = createConnection("cli2"); @@ -662,15 +669,14 @@ public void testAllConsumed() throws Exception { session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); producer = session.createProducer(null); - sent = 0; for (int i = 0; i < 2; i++) { - Message message = session.createMessage(); + final Message message = session.createMessage(); message.setStringProperty("filter", i==1 ? "true" : "false"); producer.send(topic, message); - sent++; } - LOG.info("sent: " + sent); - Thread.sleep(1 * 1000); + LOG.info("sent: 2"); + assertTrue("second batch enqueued to topic", + Wait.waitFor(() -> broker.getDestination(topic).getDestinationStatistics().getEnqueues().getCount() >= sent + 2, 5000, 100)); session.close(); con.close(); @@ -678,13 +684,14 @@ public void testAllConsumed() throws Exception { con = createConnection("cli1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); - listener = new DurableSubscriptionOfflineTestListener(); - consumer.setMessageListener(listener); - Thread.sleep(3 * 1000); + final DurableSubscriptionOfflineTestListener listener2 = new DurableSubscriptionOfflineTestListener(); + consumer.setMessageListener(listener2); + assertTrue("cli1 got 1 new filtered message", + Wait.waitFor(() -> listener2.count >= 1, 5000, 100)); session.close(); con.close(); - assertEquals(1, listener.count); + assertEquals(1, listener2.count); } // https://issues.apache.org/jira/browse/AMQ-3190 @@ -748,8 +755,8 @@ public void testNoMissOnMatchingSubAfterRestart() throws Exception { // pick up the first of the next twenty messages con = createConnection("cli2"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); - Message m = consumer.receive(3000); + final MessageConsumer consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); + final Message m = consumer.receive(3000); assertEquals("is message 10", 10, m.getIntProperty("ID")); session.close(); @@ -758,11 +765,11 @@ public void testNoMissOnMatchingSubAfterRestart() throws Exception { // pick up the first few messages for client1 con = createConnection("cli1"); session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - consumer = session.createDurableSubscriber(topic, "SubsId", filter, true); - m = consumer.receive(3000); - assertEquals("is message 0", 0, m.getIntProperty("ID")); - m = consumer.receive(3000); - assertEquals("is message 10", 10, m.getIntProperty("ID")); + final MessageConsumer consumer1 = session.createDurableSubscriber(topic, "SubsId", filter, true); + final Message m1 = consumer1.receive(3000); + assertEquals("is message 0", 0, m1.getIntProperty("ID")); + final Message m2 = consumer1.receive(3000); + assertEquals("is message 10", 10, m2.getIntProperty("ID")); session.close(); con.close(); @@ -771,21 +778,21 @@ public void testNoMissOnMatchingSubAfterRestart() throws Exception { @org.junit.Test(timeout = 640000) public void testInactiveSubscribeAfterBrokerRestart() throws Exception { final int messageCount = 20; - Connection alwaysOnCon = createConnection("subs1"); - Connection tearDownFacCon = createConnection("subs2"); - Session awaysOnCon = alwaysOnCon.createSession(false, Session.AUTO_ACKNOWLEDGE); - Session tearDownCon = tearDownFacCon.createSession(false, Session.AUTO_ACKNOWLEDGE); - ActiveMQTopic topic = new ActiveMQTopic("TEST.FOO"); - String consumerName = "consumerName"; - String tearDownconsumerName = "tearDownconsumerName"; + final Connection alwaysOnCon = createConnection("subs1"); + final Connection tearDownFacCon = createConnection("subs2"); + final Session awaysOnCon = alwaysOnCon.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session tearDownCon = tearDownFacCon.createSession(false, Session.AUTO_ACKNOWLEDGE); + final ActiveMQTopic topic = new ActiveMQTopic("TEST.FOO"); + final String consumerName = "consumerName"; + final String tearDownconsumerName = "tearDownconsumerName"; // Setup consumers - MessageConsumer remoteConsumer = awaysOnCon.createDurableSubscriber(topic, consumerName); + final MessageConsumer remoteConsumer = awaysOnCon.createDurableSubscriber(topic, consumerName); MessageConsumer remoteConsumer2 = tearDownCon.createDurableSubscriber(topic, tearDownconsumerName); - DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener("listener"); + final DurableSubscriptionOfflineTestListener listener = new DurableSubscriptionOfflineTestListener("listener"); remoteConsumer.setMessageListener(listener); remoteConsumer2.setMessageListener(listener); // Setup producer - MessageProducer localProducer = awaysOnCon.createProducer(topic); + final MessageProducer localProducer = awaysOnCon.createProducer(topic); localProducer.setDeliveryMode(DeliveryMode.PERSISTENT); // Send messages for (int i = 0; i < messageCount; i++) { @@ -793,25 +800,18 @@ public void testInactiveSubscribeAfterBrokerRestart() throws Exception { remoteConsumer2.close(); tearDownFacCon.close(); } - Message test = awaysOnCon.createTextMessage("test-" + i); + final Message test = awaysOnCon.createTextMessage("test-" + i); localProducer.send(test); } destroyBroker(); createBroker(false); - Connection reconnectCon = createConnection("subs2"); - Session reconnectSession = reconnectCon.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Connection reconnectCon = createConnection("subs2"); + final Session reconnectSession = reconnectCon.createSession(false, Session.AUTO_ACKNOWLEDGE); remoteConsumer2 = reconnectSession.createDurableSubscriber(topic, tearDownconsumerName); remoteConsumer2.setMessageListener(listener); LOG.info("waiting for messages to flow"); - Wait.waitFor(new Wait.Condition() { - @Override - public boolean isSatisified() throws Exception { - return listener.count >= messageCount * 2; - } - }); - assertTrue("At least message " + messageCount * 2 + - " must be received, count=" + listener.count, - messageCount * 2 <= listener.count); + assertTrue("At least message " + messageCount * 2 + " must be received, count=" + listener.count, + Wait.waitFor(() -> listener.count >= messageCount * 2)); awaysOnCon.close(); reconnectCon.close(); } diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionUnsubscribeTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionUnsubscribeTest.java index bc87936f428..f1fbcea7e05 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionUnsubscribeTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/DurableSubscriptionUnsubscribeTest.java @@ -39,6 +39,7 @@ import org.apache.activemq.command.ActiveMQTopic; import org.apache.activemq.command.RemoveSubscriptionInfo; import org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter; +import org.apache.activemq.util.Wait; import org.junit.experimental.categories.Category; import org.apache.activemq.test.annotations.ParallelTest; @@ -77,8 +78,7 @@ public void doJMXUnsubscribe(boolean restart) throws Exception { createSubscriptions(); createAdvisorySubscription(); - Thread.sleep(1000); - assertCount(100, 0); + waitForCount(100, 0); if (restart) { restartBroker(); @@ -86,21 +86,20 @@ public void doJMXUnsubscribe(boolean restart) throws Exception { assertCount(100, 0); } - ObjectName[] subs = broker.getAdminView().getInactiveDurableTopicSubscribers(); + final ObjectName[] subs = broker.getAdminView().getInactiveDurableTopicSubscribers(); for (int i = 0; i < subs.length; i++) { - ObjectName subName = subs[i]; - DurableSubscriptionViewMBean sub = (DurableSubscriptionViewMBean)broker.getManagementContext().newProxyInstance(subName, DurableSubscriptionViewMBean.class, true); + final ObjectName subName = subs[i]; + final DurableSubscriptionViewMBean sub = (DurableSubscriptionViewMBean)broker.getManagementContext().newProxyInstance(subName, DurableSubscriptionViewMBean.class, true); sub.destroy(); if (i % 20 == 0) { - Thread.sleep(1000); - assertCount(100 - i - 1, 0); + final int expectedAll = 100 - i - 1; + waitForCount(expectedAll, 0); } } - Thread.sleep(1000); - assertCount(0, 0); + waitForCount(0, 0); if (restart) { restartBroker(); @@ -113,30 +112,25 @@ public void doConnectionUnsubscribe(boolean restart) throws Exception { createSubscriptions(); createAdvisorySubscription(); - Thread.sleep(1000); - assertCount(100, 0); + waitForCount(100, 0); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId1"); - Thread.sleep(1000); - assertCount(100, 1); + waitForCount(100, 1); - Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); session2.createDurableSubscriber(topic, "SubsId2"); - Thread.sleep(1000); - assertCount(100, 2); + waitForCount(100, 2); session.close(); - Thread.sleep(1000); - assertCount(100, 1); + waitForCount(100, 1); session2.close(); - Thread.sleep(1000); - assertCount(100, 0); + waitForCount(100, 0); if (restart) { restartBroker(); @@ -150,13 +144,12 @@ public void doConnectionUnsubscribe(boolean restart) throws Exception { session.close(); if (i % 20 == 0) { - Thread.sleep(1000); - assertCount(100 - i - 1, 0); + final int expectedAll = 100 - i - 1; + waitForCount(expectedAll, 0); } } - Thread.sleep(1000); - assertCount(0, 0); + waitForCount(0, 0); if (restart) { restartBroker(); @@ -169,8 +162,7 @@ public void doDirectUnsubscribe(boolean restart) throws Exception { createSubscriptions(); createAdvisorySubscription(); - Thread.sleep(1000); - assertCount(100, 0); + waitForCount(100, 0); if (restart) { restartBroker(); @@ -179,17 +171,17 @@ public void doDirectUnsubscribe(boolean restart) throws Exception { } for (int i = 0; i < 100; i++) { - RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); + final RemoveSubscriptionInfo info = new RemoveSubscriptionInfo(); info.setClientId(getName()); info.setSubscriptionName("SubsId" + i); - ConnectionContext context = new ConnectionContext(); + final ConnectionContext context = new ConnectionContext(); context.setBroker(broker.getRegionBroker()); context.setClientId(getName()); broker.getBroker().removeSubscription(context, info); if (i % 20 == 0) { - Thread.sleep(1000); - assertCount(100 - i - 1, 0); + final int expectedAll = 100 - i - 1; + waitForCount(expectedAll, 0); } } @@ -204,7 +196,7 @@ public void doDirectUnsubscribe(boolean restart) throws Exception { private void createSubscriptions() throws Exception { for (int i = 0; i < 100; i++) { - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); session.createDurableSubscriber(topic, "SubsId" + i); session.close(); } @@ -213,28 +205,44 @@ private void createSubscriptions() throws Exception { private final AtomicInteger advisories = new AtomicInteger(0); private void createAdvisorySubscription() throws Exception { - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer advisoryConsumer = session.createConsumer(AdvisorySupport.getConsumerAdvisoryTopic(topic)); - advisoryConsumer.setMessageListener(new MessageListener() { - @Override - public void onMessage(Message message) { - if (((ActiveMQMessage)message).getDataStructure() instanceof RemoveSubscriptionInfo) { - advisories.incrementAndGet(); - } + final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer advisoryConsumer = session.createConsumer(AdvisorySupport.getConsumerAdvisoryTopic(topic)); + advisoryConsumer.setMessageListener(message -> { + if (((ActiveMQMessage)message).getDataStructure() instanceof RemoveSubscriptionInfo) { + advisories.incrementAndGet(); } }); } + /** + * Waits for the subscription counts to reach the expected values, then performs full assertion. + * Uses Wait.waitFor to poll the inactive durable subscriber count via the admin view, + * replacing unreliable Thread.sleep-based synchronization. + */ + private void waitForCount(final int all, final int active) throws Exception { + final int expectedInactive = all - active; + assertTrue("inactive durable subscriber count should reach " + expectedInactive, + Wait.waitFor(() -> { + final ObjectName[] inactiveSubs = broker.getAdminView().getInactiveDurableTopicSubscribers(); + final ObjectName[] activeSubs = broker.getAdminView().getDurableTopicSubscribers(); + return inactiveSubs.length == expectedInactive && activeSubs.length == active; + }, 5000, 100)); + // Wait for all advisory messages to arrive (100 = all + advisories) + assertTrue("advisory count should reach expected total", + Wait.waitFor(() -> all + advisories.get() >= 100, 5000, 100)); + assertCount(all, active); + } + private void assertCount(int all, int active) throws Exception { - int inactive = all - active; + final int inactive = all - active; // broker check - Destination destination = broker.getDestination(topic); - List subs = destination.getConsumers(); + final Destination destination = broker.getDestination(topic); + final List subs = destination.getConsumers(); int cActive = 0, cInactive = 0; - for (Subscription sub: subs) { + for (final Subscription sub: subs) { if (sub instanceof DurableTopicSubscription) { - DurableTopicSubscription durable = (DurableTopicSubscription) sub; + final DurableTopicSubscription durable = (DurableTopicSubscription) sub; if (durable.isActive()) cActive++; else @@ -261,8 +269,8 @@ private void assertCount(int all, int active) throws Exception { private int countMBean() throws MalformedObjectNameException, InstanceNotFoundException { int count = 0; for (int i = 0; i < 100; i++) { - String name = "org.apache.activemq:BrokerName=" + getName() + ",Type=Subscription,active=false,name=" + getName() + "_SubsId" + i; - ObjectName sub = new ObjectName(name); + final String name = "org.apache.activemq:BrokerName=" + getName() + ",Type=Subscription,active=false,name=" + getName() + "_SubsId" + i; + final ObjectName sub = new ObjectName(name); try { broker.getManagementContext().getObjectInstance(sub); count++; @@ -281,7 +289,7 @@ private void startBroker(boolean deleteMessages) throws Exception { broker.setBrokerName(getName()); broker.setPersistent(true); - KahaDBPersistenceAdapter persistenceAdapter = new KahaDBPersistenceAdapter(); + final KahaDBPersistenceAdapter persistenceAdapter = new KahaDBPersistenceAdapter(); persistenceAdapter.setDirectory(new File("activemq-data/" + getName())); broker.setPersistenceAdapter(persistenceAdapter); if (deleteMessages) { @@ -335,9 +343,9 @@ protected void tearDown() throws Exception { @Override protected Connection createConnection() throws Exception { - Connection rc = super.createConnection(); + final Connection rc = super.createConnection(); rc.setClientID(getName()); rc.start(); return rc; } -} \ No newline at end of file +} diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopBrokerTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopBrokerTest.java index 267db6a9b38..de53153361d 100644 --- a/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopBrokerTest.java +++ b/activemq-unit-tests/src/test/java/org/apache/activemq/usecases/StartAndStopBrokerTest.java @@ -18,8 +18,6 @@ import java.net.URI; -import jakarta.jms.JMSException; - import junit.framework.TestCase; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.broker.BrokerFactory; @@ -29,7 +27,7 @@ /** * @author Oliver Belikan - * + * */ @Category(ParallelTest.class) public class StartAndStopBrokerTest extends TestCase { @@ -39,11 +37,12 @@ public void testStartupShutdown() throws Exception { System.setProperty("activemq.persistenceAdapter", "org.apache.activemq.store.vm.VMPersistenceAdapter"); - // configuration of container and all protocolls + // configuration of container and all protocols BrokerService broker = createBroker(); - // start a client - ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:9100"); + // start a client using the dynamically assigned port + final String connectUri = broker.getTransportConnectors().get(0).getConnectUri().toString(); + ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectUri); factory.createConnection(); // stop activemq broker @@ -52,8 +51,9 @@ public void testStartupShutdown() throws Exception { // start activemq broker again broker = createBroker(); - // start a client again - factory = new ActiveMQConnectionFactory("tcp://localhost:9100"); + // start a client again using the new dynamically assigned port + final String connectUri2 = broker.getTransportConnectors().get(0).getConnectUri().toString(); + factory = new ActiveMQConnectionFactory(connectUri2); factory.createConnection(); // stop activemq broker @@ -61,15 +61,15 @@ public void testStartupShutdown() throws Exception { } - protected BrokerService createBroker() throws JMSException { + protected BrokerService createBroker() { BrokerService broker = null; try { broker = BrokerFactory.createBroker(new URI("broker://()/localhost")); broker.setBrokerName("DefaultBroker"); - broker.addConnector("tcp://localhost:9100"); + broker.addConnector("tcp://localhost:0"); broker.setUseShutdownHook(false); - + broker.start(); } catch (Exception e) { e.printStackTrace(); diff --git a/pom.xml b/pom.xml index 61751cb668e..6071365f307 100644 --- a/pom.xml +++ b/pom.xml @@ -981,6 +981,7 @@ 1 false ${surefire.forkedProcessTimeout} + all false true