/* * Copyright 2005-2014 Red Hat, Inc. * Red Hat licenses this file to you under the Apache License, version * 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package org.apache.activemq.artemis.tests.extras.byteman; import java.util.concurrent.CountDownLatch; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.api.core.client.ClientMessage; import org.apache.activemq.artemis.api.core.client.ClientProducer; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.management.CoreNotificationType; import org.apache.activemq.artemis.api.core.management.ManagementHelper; import org.apache.activemq.artemis.core.server.cluster.MessageFlowRecord; import org.apache.activemq.artemis.core.server.cluster.impl.ClusterConnectionBridge; import org.apache.activemq.artemis.core.server.cluster.impl.ClusterConnectionImpl; import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType; import org.apache.activemq.artemis.core.server.management.Notification; import org.apache.activemq.artemis.tests.integration.cluster.distribution.ClusterTestBase; import org.jboss.byteman.contrib.bmunit.BMRule; import org.jboss.byteman.contrib.bmunit.BMRules; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * This will simulate a failure of a failure. * The bridge could eventually during a race or multiple failures not be able to reconnect because it failed again. * this should make the bridge to always reconnect itself. */ @RunWith(BMUnitRunner.class) public class ClusteredBridgeReconnectTest extends ClusterTestBase { static ThreadLocal<Boolean> inConnect = new ThreadLocal<>(); public static void enterConnect() { inConnect.set(Boolean.TRUE); } public static void exitConnect() { inConnect.set(null); } public static volatile boolean shouldFail = false; public static void send() { if (inConnect.get() != null) { if (shouldFail) { shouldFail = false; throw new NullPointerException("just because it's a test..."); } } } @Test @BMRules( rules = {@BMRule( name = "enter", targetClass = "org.apache.activemq.artemis.core.server.cluster.impl.BridgeImpl", targetMethod = "connect", targetLocation = "ENTRY", action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredBridgeReconnectTest.enterConnect();"), @BMRule( name = "exit", targetClass = "org.apache.activemq.artemis.core.server.cluster.impl.BridgeImpl", targetMethod = "connect", targetLocation = "EXIT", action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredBridgeReconnectTest.exitConnect();"), @BMRule( name = "send", targetClass = "org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl", targetMethod = "send(org.apache.activemq.artemis.core.protocol.core.Packet)", targetLocation = "EXIT", action = "org.apache.activemq.artemis.tests.extras.byteman.ClusteredBridgeReconnectTest.send();") }) public void testReconnectBridge() throws Exception { setupServer(0, isFileStorage(), isNetty()); setupServer(1, isFileStorage(), isNetty()); setupClusterConnection("cluster0", "queues", MessageLoadBalancingType.ON_DEMAND, 1, isNetty(), 0, 1); setupClusterConnection("cluster1", "queues", MessageLoadBalancingType.ON_DEMAND, 1, isNetty(), 1, 0); startServers(0, 1); setupSessionFactory(0, isNetty()); setupSessionFactory(1, isNetty()); createQueue(0, "queues.testaddress", "queue0", null, true); createQueue(1, "queues.testaddress", "queue0", null, true); addConsumer(0, 0, "queue0", null); addConsumer(1, 1, "queue0", null); waitForBindings(0, "queues.testaddress", 1, 1, true); waitForBindings(1, "queues.testaddress", 1, 1, true); waitForBindings(0, "queues.testaddress", 1, 1, false); waitForBindings(1, "queues.testaddress", 1, 1, false); ClientSession session0 = sfs[0].createSession(); ClientSession session1 = sfs[0].createSession(); session0.start(); session1.start(); ClientProducer producer = session0.createProducer("queues.testaddress"); int NUMBER_OF_MESSAGES = 100; Assert.assertEquals(1, servers[0].getClusterManager().getClusterConnections().size()); ClusterConnectionImpl connection = servers[0].getClusterManager().getClusterConnections().toArray(new ClusterConnectionImpl[0])[0]; Assert.assertEquals(1, connection.getRecords().size()); MessageFlowRecord record = connection.getRecords().values().toArray(new MessageFlowRecord[1])[0]; ClusterConnectionBridge bridge = (ClusterConnectionBridge) record.getBridge(); for (int i = 0; i < NUMBER_OF_MESSAGES; i++) { ClientMessage msg = session0.createMessage(true); producer.send(msg); session0.commit(); if (i == 17) { shouldFail = true; bridge.getSessionFactory().getConnection().fail(new ActiveMQException("failed once!")); } } int cons0Count = 0, cons1Count = 0; while (true) { ClientMessage msg = consumers[0].getConsumer().receive(1000); if (msg == null) { break; } cons0Count++; msg.acknowledge(); session0.commit(); } while (true) { ClientMessage msg = consumers[1].getConsumer().receive(1000); if (msg == null) { break; } cons1Count++; msg.acknowledge(); session1.commit(); } Assert.assertEquals("cons0 = " + cons0Count + ", cons1 = " + cons1Count, NUMBER_OF_MESSAGES, cons0Count + cons1Count); session0.commit(); session1.commit(); stopServers(0, 1); } static CountDownLatch latch; static CountDownLatch latch2; static Thread main; public static void pause(SimpleString clusterName) { if (clusterName.toString().startsWith("queue0")) { try { latch2.countDown(); latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void pause2(Notification notification) { if (notification.getType() == CoreNotificationType.BINDING_REMOVED) { SimpleString clusterName = notification.getProperties().getSimpleStringProperty(ManagementHelper.HDR_CLUSTER_NAME); boolean inMain = main == Thread.currentThread(); if (clusterName.toString().startsWith("queue0") && !inMain) { try { latch2.countDown(); latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void restart2() { latch.countDown(); } @Override @Before public void setUp() throws Exception { super.setUp(); shouldFail = false; } @Override @After public void tearDown() throws Exception { closeAllConsumers(); closeAllSessionFactories(); closeAllServerLocatorsFactories(); super.tearDown(); } public boolean isNetty() { return true; } }