/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.artemis.tests.extras.jms.bridge;
import javax.transaction.TransactionManager;
import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.jms.bridge.ConnectionFactoryFactory;
import org.apache.activemq.artemis.jms.bridge.DestinationFactory;
import org.apache.activemq.artemis.jms.bridge.QualityOfServiceMode;
import org.apache.activemq.artemis.jms.bridge.impl.JMSBridgeImpl;
import org.junit.Before;
import org.junit.Test;
/**
* A JMSBridgeClusteredTest
* <br>
* Tests of jms bridge using HA connection factories.
*/
public class JMSBridgeClusteredTest extends ClusteredBridgeTestBase {
private ServerGroup sourceServer;
private ServerGroup targetServer;
private String sourceQueueName = "SourceQueue";
private String targetQueueName = "TargetQueue";
@Override
@Before
public void setUp() throws Exception {
super.setUp();
sourceServer = createServerGroup("source-server");
targetServer = createServerGroup("target-server");
sourceServer.start();
targetServer.start();
sourceServer.createQueue(sourceQueueName);
targetServer.createQueue(targetQueueName);
}
@Test
public void testBridgeOnFailoverXA() throws Exception {
performSourceAndTargetCrashAndFailover(QualityOfServiceMode.ONCE_AND_ONLY_ONCE);
}
@Test
public void testBridgeOnFailoverDupsOk() throws Exception {
performSourceAndTargetCrashAndFailover(QualityOfServiceMode.DUPLICATES_OK);
}
@Test
public void testBridgeOnFailoverAtMostOnce() throws Exception {
performSourceAndTargetCrashAndFailover(QualityOfServiceMode.AT_MOST_ONCE);
}
@Test
public void testCrashAndFailoverWithMessagesXA() throws Exception {
performSourceAndTargetCrashAndFailoverWithMessages(QualityOfServiceMode.ONCE_AND_ONLY_ONCE);
}
//test messages are correctly bridged when failover happens during a batch send.
//first send some messages, make sure bridge doesn't send it (below batch size)
//then crash the live
//then send more messages
//then receive those messages, no more, no less.
//this test are valid for ONCE_AND_ONLY_ONCE and AT_MOST_ONCE.
//with DUPS_OK the test failed because some messages are delivered again
//after failover, which is fine as in this mode duplication is allowed.
public void performSourceAndTargetCrashAndFailoverWithMessages(QualityOfServiceMode mode) throws Exception {
JMSBridgeImpl bridge = null;
TransactionManager txMgr = null;
try {
ConnectionFactoryFactory sourceCFF = sourceServer.getConnectionFactoryFactory();
ConnectionFactoryFactory targetCFF = targetServer.getConnectionFactoryFactory();
DestinationFactory sourceQueueFactory = sourceServer.getDestinationFactory(sourceQueueName);
DestinationFactory targetQueueFactory = targetServer.getDestinationFactory(targetQueueName);
//even number
final int batchSize = 4;
bridge = new JMSBridgeImpl(sourceCFF, targetCFF, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, mode, batchSize, -1, null, null, false).setBridgeName("test-bridge");
txMgr = newTransactionManager();
bridge.setTransactionManager(txMgr);
//start the bridge
bridge.start();
System.out.println("started bridge");
final int NUM_MESSAGES = batchSize / 2;
//send some messages to source
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
//receive from target, no message should be received.
receiveMessages(targetServer, targetQueueName, 0);
//now crash target server
targetServer.crashLive();
//send more
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
receiveMessages(targetServer, targetQueueName, batchSize);
//send some again
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
//check no messages arrived.
receiveMessages(targetServer, targetQueueName, 0);
//now crash source server
sourceServer.crashLive();
//verify bridge still work
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
receiveMessages(targetServer, targetQueueName, batchSize);
} finally {
if (bridge != null) {
bridge.stop();
}
}
}
/*
* Deploy a bridge, source and target queues are in
* separate live/backup pairs. Source and Target CF are ha.
* Test the bridge work when the live servers crash.
*/
private void performSourceAndTargetCrashAndFailover(QualityOfServiceMode mode) throws Exception {
JMSBridgeImpl bridge = null;
TransactionManager txMgr = null;
try {
ConnectionFactoryFactory sourceCFF = sourceServer.getConnectionFactoryFactory();
ConnectionFactoryFactory targetCFF = targetServer.getConnectionFactoryFactory();
DestinationFactory sourceQueueFactory = sourceServer.getDestinationFactory(sourceQueueName);
DestinationFactory targetQueueFactory = targetServer.getDestinationFactory(targetQueueName);
bridge = new JMSBridgeImpl(sourceCFF, targetCFF, sourceQueueFactory, targetQueueFactory, null, null, null, null, null, 1000, -1, mode, 10, 1000, null, null, false).setBridgeName("test-bridge");
txMgr = newTransactionManager();
bridge.setTransactionManager(txMgr);
//start the bridge
bridge.start();
final int NUM_MESSAGES = 10;
//send some messages to source
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
//receive from target
receiveMessages(targetServer, targetQueueName, NUM_MESSAGES);
//now crash target server
targetServer.crashLive();
//verify bridge still works
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
receiveMessages(targetServer, targetQueueName, NUM_MESSAGES);
//now crash source server
sourceServer.crashLive();
//verify bridge still work
sendMessages(sourceServer, sourceQueueName, NUM_MESSAGES);
receiveMessages(targetServer, targetQueueName, NUM_MESSAGES, mode == QualityOfServiceMode.ONCE_AND_ONLY_ONCE);
} finally {
if (bridge != null) {
bridge.stop();
}
}
}
private void sendMessages(ServerGroup server, String queueName, int num) throws ActiveMQException {
server.sendMessages(queueName, num);
}
private void receiveMessages(ServerGroup server,
String queueName,
int num,
boolean checkDup) throws ActiveMQException {
try {
server.receiveMessages(queueName, num, checkDup);
} catch (ActiveMQException e) {
e.printStackTrace();
throw e;
}
}
private void receiveMessages(ServerGroup server, String queueName, int num) throws ActiveMQException {
try {
server.receiveMessages(queueName, num, false);
} catch (ActiveMQException e) {
e.printStackTrace();
throw e;
}
}
protected TransactionManager newTransactionManager() {
return new TransactionManagerImple();
}
}