/*
* 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.util;
import javax.naming.Context;
import javax.transaction.xa.XAException;
import javax.transaction.xa.Xid;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.lang.ref.WeakReference;
import java.net.ServerSocket;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.artemis.api.core.ActiveMQBuffer;
import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.ActiveMQExceptionType;
import org.apache.activemq.artemis.api.core.ICoreMessage;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.api.core.Pair;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
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.client.ClientSessionFactory;
import org.apache.activemq.artemis.api.core.client.ServerLocator;
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl;
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryInternal;
import org.apache.activemq.artemis.core.client.impl.ServerLocatorImpl;
import org.apache.activemq.artemis.core.client.impl.Topology;
import org.apache.activemq.artemis.core.client.impl.TopologyMemberImpl;
import org.apache.activemq.artemis.core.config.ClusterConnectionConfiguration;
import org.apache.activemq.artemis.core.config.Configuration;
import org.apache.activemq.artemis.core.config.StoreConfiguration;
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
import org.apache.activemq.artemis.core.config.storage.DatabaseStorageConfiguration;
import org.apache.activemq.artemis.core.io.SequentialFileFactory;
import org.apache.activemq.artemis.core.io.nio.NIOSequentialFileFactory;
import org.apache.activemq.artemis.core.journal.PreparedTransactionInfo;
import org.apache.activemq.artemis.core.journal.RecordInfo;
import org.apache.activemq.artemis.core.journal.impl.JournalFile;
import org.apache.activemq.artemis.core.journal.impl.JournalImpl;
import org.apache.activemq.artemis.core.journal.impl.JournalReaderCallback;
import org.apache.activemq.artemis.core.message.impl.CoreMessage;
import org.apache.activemq.artemis.core.paging.PagingStore;
import org.apache.activemq.artemis.core.persistence.impl.journal.OperationContextImpl;
import org.apache.activemq.artemis.core.postoffice.Binding;
import org.apache.activemq.artemis.core.postoffice.Bindings;
import org.apache.activemq.artemis.core.postoffice.PostOffice;
import org.apache.activemq.artemis.core.postoffice.QueueBinding;
import org.apache.activemq.artemis.core.postoffice.impl.LocalQueueBinding;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnector;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMRegistry;
import org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnector;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.core.server.ActiveMQServers;
import org.apache.activemq.artemis.core.server.JournalType;
import org.apache.activemq.artemis.core.server.MessageReference;
import org.apache.activemq.artemis.core.server.NodeManager;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.server.cluster.ClusterConnection;
import org.apache.activemq.artemis.core.server.cluster.ClusterManager;
import org.apache.activemq.artemis.core.server.cluster.RemoteQueueBinding;
import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
import org.apache.activemq.artemis.core.server.impl.Activation;
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
import org.apache.activemq.artemis.core.server.impl.SharedNothingBackupActivation;
import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy;
import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
import org.apache.activemq.artemis.core.transaction.impl.XidImpl;
import org.apache.activemq.artemis.jdbc.store.drivers.JDBCUtils;
import org.apache.activemq.artemis.jdbc.store.sql.SQLProvider;
import org.apache.activemq.artemis.jlibaio.LibaioContext;
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
import org.apache.activemq.artemis.spi.core.security.jaas.InVMLoginModule;
import org.apache.activemq.artemis.utils.ActiveMQThreadFactory;
import org.apache.activemq.artemis.utils.Env;
import org.apache.activemq.artemis.utils.FileUtil;
import org.apache.activemq.artemis.utils.OrderedExecutorFactory;
import org.apache.activemq.artemis.utils.RandomUtil;
import org.apache.activemq.artemis.utils.ThreadLeakCheckRule;
import org.apache.activemq.artemis.utils.UUIDGenerator;
import org.jboss.logging.Logger;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.TestName;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
/**
* Base class with basic utilities on starting up a basic server
*/
public abstract class ActiveMQTestBase extends Assert {
static {
Env.setTestEnv(true);
}
private static final Logger logger = Logger.getLogger(ActiveMQTestBase.class);
@Rule
public ThreadLeakCheckRule leakCheckRule = new ThreadLeakCheckRule();
public static final String TARGET_TMP = "./target/tmp";
public static final String INVM_ACCEPTOR_FACTORY = InVMAcceptorFactory.class.getCanonicalName();
public static final String INVM_CONNECTOR_FACTORY = InVMConnectorFactory.class.getCanonicalName();
public static final String NETTY_ACCEPTOR_FACTORY = NettyAcceptorFactory.class.getCanonicalName();
public static final String NETTY_CONNECTOR_FACTORY = NettyConnectorFactory.class.getCanonicalName();
public static final String CLUSTER_PASSWORD = "UnitTestsClusterPassword";
/**
* Add a "sendCallNumber" property to messages sent using helper classes. Meant to help in
* debugging.
*/
private static final String SEND_CALL_NUMBER = "sendCallNumber";
private static final String OS_TYPE = System.getProperty("os.name").toLowerCase();
private static final int DEFAULT_UDP_PORT;
private static final ActiveMQServerLogger log = ActiveMQServerLogger.LOGGER;
protected static final long WAIT_TIMEOUT = 30000;
// There is a verification about thread leakages. We only fail a single thread when this happens
private static Set<Thread> alreadyFailedThread = new HashSet<>();
private final Collection<ActiveMQServer> servers = new ArrayList<>();
private final Collection<ServerLocator> locators = new ArrayList<>();
private final Collection<ClientSessionFactory> sessionFactories = new ArrayList<>();
private final Collection<ClientSession> clientSessions = new HashSet<>();
private final Collection<ClientConsumer> clientConsumers = new HashSet<>();
private final Collection<ClientProducer> clientProducers = new HashSet<>();
private final Collection<ActiveMQComponent> otherComponents = new HashSet<>();
private final Set<ExecutorService> executorSet = new HashSet<>();
private String testDir;
private int sendMsgCount = 0;
@Rule
public TestName name = new TestName();
@Rule
public TemporaryFolder temporaryFolder;
@Rule
// This Custom rule will remove any files under ./target/tmp
// including anything created previously by TemporaryFolder
public RemoveFolder folder = new RemoveFolder(TARGET_TMP);
@Rule
public TestRule watcher = new TestWatcher() {
@Override
protected void starting(Description description) {
log.info(String.format("#*#*# Starting test: %s()...", description.getMethodName()));
}
@Override
protected void finished(Description description) {
log.info(String.format("#*#*# Finished test: %s()...", description.getMethodName()));
}
};
@After
public void shutdownDerby() {
try {
DriverManager.getConnection("jdbc:derby:;shutdown=true");
} catch (Exception ignored) {
}
}
static {
Random random = new Random();
DEFAULT_UDP_PORT = 6000 + random.nextInt(1000);
}
public ActiveMQTestBase() {
File parent = new File(TARGET_TMP);
parent.mkdirs();
temporaryFolder = new TemporaryFolder(parent);
}
protected <T> T serialClone(Object object) throws Exception {
System.out.println("object::" + object);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream obOut = new ObjectOutputStream(bout);
obOut.writeObject(object);
ByteArrayInputStream binput = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream obinp = new ObjectInputStream(binput);
return (T) obinp.readObject();
}
@After
public void tearDown() throws Exception {
closeAllSessionFactories();
closeAllServerLocatorsFactories();
try {
assertAllClientConsumersAreClosed();
assertAllClientProducersAreClosed();
assertAllClientSessionsAreClosed();
} finally {
synchronized (servers) {
for (ActiveMQServer server : servers) {
if (server == null) {
continue;
}
try {
final ClusterManager clusterManager = server.getClusterManager();
if (clusterManager != null) {
for (ClusterConnection cc : clusterManager.getClusterConnections()) {
stopComponent(cc);
}
}
} catch (Exception e) {
// no-op
}
stopComponentOutputExceptions(server);
}
servers.clear();
}
closeAllOtherComponents();
ArrayList<Exception> exceptions;
try {
exceptions = checkCsfStopped();
} finally {
cleanupPools();
}
for (ExecutorService s : executorSet) {
s.shutdown();
}
InVMConnector.resetThreadPool();
assertAllExecutorsFinished();
//clean up pools before failing
if (!exceptions.isEmpty()) {
for (Exception exception : exceptions) {
exception.printStackTrace();
}
fail("Client Session Factories still trying to reconnect, see above to see where created");
}
Map<Thread, StackTraceElement[]> threadMap = Thread.getAllStackTraces();
for (Map.Entry<Thread, StackTraceElement[]> entry : threadMap.entrySet()) {
Thread thread = entry.getKey();
StackTraceElement[] stack = entry.getValue();
for (StackTraceElement stackTraceElement : stack) {
if (stackTraceElement.getMethodName().contains("getConnectionWithRetry") && !alreadyFailedThread.contains(thread)) {
alreadyFailedThread.add(thread);
System.out.println(threadDump(this.getName() + " has left threads running. Look at thread " +
thread.getName() +
" id = " +
thread.getId() +
" has running locators on test " +
this.getName() +
" on this following dump"));
fail("test '" + getName() + "' left serverlocator running, this could effect other tests");
} else if (stackTraceElement.getMethodName().contains("BroadcastGroupImpl.run") && !alreadyFailedThread.contains(thread)) {
alreadyFailedThread.add(thread);
System.out.println(threadDump(this.getName() + " has left threads running. Look at thread " +
thread.getName() +
" id = " +
thread.getId() +
" is still broadcasting " +
this.getName() +
" on this following dump"));
fail("test left broadcastgroupimpl running, this could effect other tests");
}
}
}
if (Thread.currentThread().getContextClassLoader() == null) {
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
fail("Thread Context ClassLoader was set to null at some point before this test. We will set to this.getClass().getClassLoader(), but you are supposed to fix your tests");
}
checkFilesUsage();
}
if (InVMRegistry.instance.size() > 0) {
fail("InVMREgistry size > 0");
}
}
@Before
public void setUp() throws Exception {
sendMsgCount = 0;
testDir = temporaryFolder.getRoot().getAbsolutePath();
clearDataRecreateServerDirs();
OperationContextImpl.clearContext();
InVMRegistry.instance.clear();
// checkFreePort(TransportConstants.DEFAULT_PORT);
logAndSystemOut("#test " + getName());
}
public static void assertEqualsByteArrays(final byte[] expected, final byte[] actual) {
for (int i = 0; i < expected.length; i++) {
Assert.assertEquals("byte at index " + i, expected[i], actual[i]);
}
}
/**
* @param str
* @param sub
* @return
*/
public static int countOccurrencesOf(String str, String sub) {
if (str == null || sub == null || str.length() == 0 || sub.length() == 0) {
return 0;
}
int count = 0;
int pos = 0;
int idx;
while ((idx = str.indexOf(sub, pos)) != -1) {
++count;
pos = idx + sub.length();
}
return count;
}
protected void disableCheckThread() {
leakCheckRule.disable();
}
protected String getName() {
return name.getMethodName();
}
protected boolean isWindows() {
return (OS_TYPE.indexOf("win") >= 0);
}
protected Configuration createDefaultInVMConfig() throws Exception {
return createDefaultConfig(0, false);
}
protected Configuration createDefaultInVMConfig(final int serverID) throws Exception {
return createDefaultConfig(serverID, false);
}
protected Configuration createDefaultNettyConfig() throws Exception {
return createDefaultConfig(0, true);
}
protected Configuration createDefaultConfig(final boolean netty) throws Exception {
return createDefaultConfig(0, netty);
}
protected Configuration createDefaultJDBCConfig(boolean isNetty) throws Exception {
Configuration configuration = createDefaultConfig(isNetty);
setDBStoreType(configuration);
return configuration;
}
protected Configuration createDefaultConfig(final int serverID, final boolean netty) throws Exception {
ConfigurationImpl configuration = createBasicConfig(serverID).setJMXManagementEnabled(false).addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY, generateInVMParams(serverID), "invm"));
if (netty) {
configuration.addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, new HashMap<String, Object>(), "netty", new HashMap<String, Object>()));
}
return configuration;
}
private Configuration createDefaultConfig(final int index,
final Map<String, Object> params,
final String... acceptors) {
Configuration configuration = createBasicConfig(index);
for (String acceptor : acceptors) {
TransportConfiguration transportConfig = new TransportConfiguration(acceptor, params);
configuration.getAcceptorConfigurations().add(transportConfig);
}
return configuration;
}
protected ConfigurationImpl createBasicConfig() throws Exception {
return createBasicConfig(-1);
}
/**
* @param serverID
* @return
* @throws Exception
*/
protected ConfigurationImpl createBasicConfig(final int serverID) {
ConfigurationImpl configuration = new ConfigurationImpl().setSecurityEnabled(false).setJournalMinFiles(2).setJournalFileSize(100 * 1024).setJournalType(getDefaultJournalType()).setJournalDirectory(getJournalDir(serverID, false)).setBindingsDirectory(getBindingsDir(serverID, false)).setPagingDirectory(getPageDir(serverID, false)).setLargeMessagesDirectory(getLargeMessagesDir(serverID, false)).setJournalCompactMinFiles(0).setJournalCompactPercentage(0).setClusterPassword(CLUSTER_PASSWORD).setJournalDatasync(false);
return configuration;
}
protected void setDBStoreType(Configuration configuration) {
DatabaseStorageConfiguration dbStorageConfiguration = new DatabaseStorageConfiguration();
dbStorageConfiguration.setJdbcConnectionUrl(getTestJDBCConnectionUrl());
dbStorageConfiguration.setBindingsTableName("BINDINGS");
dbStorageConfiguration.setMessageTableName("MESSAGE");
dbStorageConfiguration.setLargeMessageTableName("LARGE_MESSAGE");
dbStorageConfiguration.setPageStoreTableName("PAGE_STORE");
dbStorageConfiguration.setJdbcDriverClassName(getJDBCClassName());
configuration.setStoreConfiguration(dbStorageConfiguration);
}
public void destroyTables(List<String> tableNames) throws Exception {
Driver driver = getDriver(getJDBCClassName());
Connection connection = driver.connect(getTestJDBCConnectionUrl(), null);
Statement statement = connection.createStatement();
try {
for (String tableName : tableNames) {
connection.setAutoCommit(false);
SQLProvider sqlProvider = JDBCUtils.getSQLProvider(getJDBCClassName(), tableName, SQLProvider.DatabaseStoreType.LARGE_MESSAGE);
try (ResultSet rs = connection.getMetaData().getTables(null, null, sqlProvider.getTableName(), null)) {
if (rs.next()) {
statement.execute("DROP TABLE " + sqlProvider.getTableName());
}
connection.commit();
} catch (SQLException e) {
connection.rollback();
}
}
} catch (Throwable e) {
e.printStackTrace();
} finally {
connection.close();
}
}
private Driver getDriver(String className) throws Exception {
try {
Driver driver = (Driver) Class.forName(className).newInstance();
// Shutdown the derby if using the derby embedded driver.
if (className.equals("org.apache.derby.jdbc.EmbeddedDriver")) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
DriverManager.getConnection("jdbc:derby:;shutdown=true");
} catch (Exception e) {
}
}
});
}
return driver;
} catch (ClassNotFoundException cnfe) {
throw new RuntimeException("Could not find class: " + className);
} catch (Exception e) {
throw new RuntimeException("Unable to instantiate driver class: ", e);
}
}
protected Map<String, Object> generateInVMParams(final int node) {
Map<String, Object> params = new HashMap<>();
params.put(org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants.SERVER_ID_PROP_NAME, node);
return params;
}
protected static final ClusterConnectionConfiguration basicClusterConnectionConfig(String connectorName,
String... connectors) {
ArrayList<String> connectors0 = new ArrayList<>();
for (String c : connectors) {
connectors0.add(c);
}
ClusterConnectionConfiguration clusterConnectionConfiguration = new ClusterConnectionConfiguration().setName("cluster1").setAddress("jms").setConnectorName(connectorName).setRetryInterval(1000).setDuplicateDetection(false).setMaxHops(1).setConfirmationWindowSize(1).setMessageLoadBalancingType(MessageLoadBalancingType.STRICT).setStaticConnectors(connectors0);
return clusterConnectionConfiguration;
}
protected final OrderedExecutorFactory getOrderedExecutor() {
final ExecutorService executor = Executors.newCachedThreadPool(ActiveMQThreadFactory.defaultThreadFactory());
executorSet.add(executor);
return new OrderedExecutorFactory(executor);
}
protected static String getUDPDiscoveryAddress() {
return System.getProperty("TEST-UDP-ADDRESS", "230.1.2.3");
}
protected static String getUDPDiscoveryAddress(final int variant) {
String value = getUDPDiscoveryAddress();
int posPoint = value.lastIndexOf('.');
int last = Integer.valueOf(value.substring(posPoint + 1));
return value.substring(0, posPoint + 1) + (last + variant);
}
public static int getUDPDiscoveryPort() {
String port = System.getProperty("TEST-UDP-PORT");
if (port != null) {
return Integer.parseInt(port);
}
return DEFAULT_UDP_PORT;
}
public static int getUDPDiscoveryPort(final int variant) {
return getUDPDiscoveryPort() + variant;
}
public static JournalType getDefaultJournalType() {
if (LibaioContext.isLoaded()) {
return JournalType.ASYNCIO;
} else {
return JournalType.NIO;
}
}
public static void forceGC() {
ThreadLeakCheckRule.forceGC();
}
/**
* Verifies whether weak references are released after a few GCs.
*
* @param references
* @throws InterruptedException
*/
public static void checkWeakReferences(final WeakReference<?>... references) {
int i = 0;
boolean hasValue = false;
do {
hasValue = false;
if (i > 0) {
forceGC();
}
for (WeakReference<?> ref : references) {
if (ref.get() != null) {
hasValue = true;
break;
}
}
} while (i++ <= 200 && hasValue);
for (WeakReference<?> ref : references) {
Assert.assertNull(ref.get());
}
}
public static String threadDump(final String msg) {
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
Map<Thread, StackTraceElement[]> stackTrace = Thread.getAllStackTraces();
out.println("*******************************************************************************");
out.println("Complete Thread dump " + msg);
for (Map.Entry<Thread, StackTraceElement[]> el : stackTrace.entrySet()) {
out.println("===============================================================================");
out.println("Thread " + el.getKey() +
" name = " +
el.getKey().getName() +
" id = " +
el.getKey().getId() +
" group = " +
el.getKey().getThreadGroup());
out.println();
for (StackTraceElement traceEl : el.getValue()) {
out.println(traceEl);
}
}
out.println("===============================================================================");
out.println("End Thread dump " + msg);
out.println("*******************************************************************************");
return str.toString();
}
/**
* Sends the message to both logger and System.out (for unit report)
*/
public void logAndSystemOut(String message, Exception e) {
System.out.println(message);
if (e != null) {
e.printStackTrace(System.out);
}
ActiveMQServerLogger log0 = ActiveMQServerLogger.LOGGER;
log0.debug(message, e);
}
/**
* Sends the message to both logger and System.out (for unit report)
*/
public void logAndSystemOut(String message) {
logAndSystemOut(message, null);
}
public static String dumpBytes(final byte[] bytes) {
StringBuffer buff = new StringBuffer();
buff.append(System.identityHashCode(bytes) + ", size: " + bytes.length + " [");
for (int i = 0; i < bytes.length; i++) {
buff.append(bytes[i]);
if (i != bytes.length - 1) {
buff.append(", ");
}
}
buff.append("]");
return buff.toString();
}
public static String dumpBytesHex(final byte[] buffer, final int bytesPerLine) {
StringBuffer buff = new StringBuffer();
buff.append("[");
for (int i = 0; i < buffer.length; i++) {
buff.append(String.format("%1$2X", buffer[i]));
if (i + 1 < buffer.length) {
buff.append(", ");
}
if ((i + 1) % bytesPerLine == 0) {
buff.append("\n ");
}
}
buff.append("]");
return buff.toString();
}
public static void assertEqualsTransportConfigurations(final TransportConfiguration[] expected,
final TransportConfiguration[] actual) {
assertEquals(expected.length, actual.length);
for (int i = 0; i < expected.length; i++) {
Assert.assertEquals("TransportConfiguration at index " + i, expected[i], actual[i]);
}
}
public static void assertEqualsBuffers(final int size, final ActiveMQBuffer expected, final ActiveMQBuffer actual) {
// assertEquals(expected.length, actual.length);
expected.readerIndex(0);
actual.readerIndex(0);
for (int i = 0; i < size; i++) {
byte b1 = expected.readByte();
byte b2 = actual.readByte();
Assert.assertEquals("byte at index " + i, b1, b2);
}
expected.resetReaderIndex();
actual.resetReaderIndex();
}
public static void assertEqualsByteArrays(final int length, final byte[] expected, final byte[] actual) {
// we check only for the given length (the arrays might be
// larger)
Assert.assertTrue(expected.length >= length);
Assert.assertTrue(actual.length >= length);
for (int i = 0; i < length; i++) {
Assert.assertEquals("byte at index " + i, expected[i], actual[i]);
}
}
public static void assertSameXids(final List<Xid> expected, final List<Xid> actual) {
Assert.assertNotNull(expected);
Assert.assertNotNull(actual);
Assert.assertEquals(expected.size(), actual.size());
for (int i = 0; i < expected.size(); i++) {
Xid expectedXid = expected.get(i);
Xid actualXid = actual.get(i);
assertEqualsByteArrays(expectedXid.getBranchQualifier(), actualXid.getBranchQualifier());
Assert.assertEquals(expectedXid.getFormatId(), actualXid.getFormatId());
assertEqualsByteArrays(expectedXid.getGlobalTransactionId(), actualXid.getGlobalTransactionId());
}
}
protected static void checkNoBinding(final Context context, final String binding) {
try {
context.lookup(binding);
Assert.fail("there must be no resource to look up for " + binding);
} catch (Exception e) {
}
}
protected static Object checkBinding(final Context context, final String binding) throws Exception {
Object o = context.lookup(binding);
Assert.assertNotNull(o);
return o;
}
/**
* @param connectorConfigs
* @return
*/
protected ArrayList<String> registerConnectors(final ActiveMQServer server,
final List<TransportConfiguration> connectorConfigs) {
// The connectors need to be pre-configured at main config object but this method is taking
// TransportConfigurations directly
// So this will first register them at the config and then generate a list of objects
ArrayList<String> connectors = new ArrayList<>();
for (TransportConfiguration tnsp : connectorConfigs) {
String name1 = RandomUtil.randomString();
server.getConfiguration().getConnectorConfigurations().put(name1, tnsp);
connectors.add(name1);
}
return connectors;
}
protected static final void checkFreePort(final int... ports) {
for (int port : ports) {
ServerSocket ssocket = null;
try {
ssocket = new ServerSocket(port);
} catch (Exception e) {
throw new IllegalStateException("port " + port + " is bound", e);
} finally {
if (ssocket != null) {
try {
ssocket.close();
} catch (IOException e) {
}
}
}
}
}
/**
* @return the testDir
*/
protected final String getTestDir() {
return testDir;
}
protected final String getTestJDBCConnectionUrl() {
return System.getProperty("jdbc.connection.url", "jdbc:derby:" + getTestDir() + File.separator + "derby;create=true");
}
protected final String getJDBCClassName() {
return System.getProperty("jdbc.driver.class", "org.apache.derby.jdbc.EmbeddedDriver");
}
protected final File getTestDirfile() {
return new File(testDir);
}
protected final void setTestDir(String testDir) {
this.testDir = testDir;
}
protected final void clearDataRecreateServerDirs() {
clearDataRecreateServerDirs(0, false);
}
protected final void clearDataRecreateServerDirs(int index, boolean backup) {
clearDataRecreateServerDirs(getTestDir(), index, backup);
}
protected void clearDataRecreateServerDirs(final String testDir1, int index, boolean backup) {
// Need to delete the root
File file = new File(testDir1);
deleteDirectory(file);
file.mkdirs();
recreateDataDirectories(testDir1, index, backup);
}
protected void recreateDataDirectories(String testDir1, int index, boolean backup) {
recreateDirectory(getJournalDir(testDir1, index, backup));
recreateDirectory(getBindingsDir(testDir1, index, backup));
recreateDirectory(getPageDir(testDir1, index, backup));
recreateDirectory(getLargeMessagesDir(testDir1, index, backup));
recreateDirectory(getClientLargeMessagesDir(testDir1));
recreateDirectory(getTemporaryDir(testDir1));
}
/**
* @return the journalDir
*/
public String getJournalDir() {
return getJournalDir(0, false);
}
protected static String getJournalDir(final String testDir1) {
return testDir1 + "/journal";
}
public String getJournalDir(final int index, final boolean backup) {
return getJournalDir(getTestDir(), index, backup);
}
public static String getJournalDir(final String testDir, final int index, final boolean backup) {
return getJournalDir(testDir) + directoryNameSuffix(index, backup);
}
/**
* @return the bindingsDir
*/
protected String getBindingsDir() {
return getBindingsDir(0, false);
}
/**
* @return the bindingsDir
*/
protected static String getBindingsDir(final String testDir1) {
return testDir1 + "/bindings";
}
/**
* @return the bindingsDir
*/
protected String getBindingsDir(final int index, final boolean backup) {
return getBindingsDir(getTestDir(), index, backup);
}
public static String getBindingsDir(final String testDir, final int index, final boolean backup) {
return getBindingsDir(testDir) + directoryNameSuffix(index, backup);
}
/**
* @return the pageDir
*/
protected String getPageDir() {
return getPageDir(0, false);
}
protected File getPageDirFile() {
return new File(getPageDir());
}
/**
* @return the pageDir
*/
protected static String getPageDir(final String testDir1) {
return testDir1 + "/page";
}
protected String getPageDir(final int index, final boolean backup) {
return getPageDir(getTestDir(), index, backup);
}
public static String getPageDir(final String testDir, final int index, final boolean backup) {
return getPageDir(testDir) + directoryNameSuffix(index, backup);
}
/**
* @return the largeMessagesDir
*/
protected String getLargeMessagesDir() {
return getLargeMessagesDir(0, false);
}
/**
* @return the largeMessagesDir
*/
protected static String getLargeMessagesDir(final String testDir1) {
return testDir1 + "/large-msg";
}
protected String getLargeMessagesDir(final int index, final boolean backup) {
return getLargeMessagesDir(getTestDir(), index, backup);
}
public static String getLargeMessagesDir(final String testDir, final int index, final boolean backup) {
return getLargeMessagesDir(testDir) + directoryNameSuffix(index, backup);
}
private static String directoryNameSuffix(int index, boolean backup) {
if (index == -1)
return "";
return index + "-" + (backup ? "B" : "L");
}
/**
* @return the clientLargeMessagesDir
*/
protected String getClientLargeMessagesDir() {
return getClientLargeMessagesDir(getTestDir());
}
/**
* @return the clientLargeMessagesDir
*/
protected String getClientLargeMessagesDir(final String testDir1) {
return testDir1 + "/client-large-msg";
}
/**
* @return the temporaryDir
*/
protected final String getTemporaryDir() {
return getTemporaryDir(getTestDir());
}
/**
* @return the temporaryDir
*/
protected String getTemporaryDir(final String testDir1) {
return testDir1 + "/temp";
}
protected static void expectActiveMQException(final String message,
final ActiveMQExceptionType errorCode,
final ActiveMQAction action) {
try {
action.run();
Assert.fail(message);
} catch (Exception e) {
Assert.assertTrue(e instanceof ActiveMQException);
Assert.assertEquals(errorCode, ((ActiveMQException) e).getType());
}
}
protected static void expectActiveMQException(final ActiveMQExceptionType errorCode, final ActiveMQAction action) {
expectActiveMQException("must throw an ActiveMQException with the expected errorCode: " + errorCode, errorCode, action);
}
protected static void expectXAException(final int errorCode, final ActiveMQAction action) {
try {
action.run();
Assert.fail("must throw a XAException with the expected errorCode: " + errorCode);
} catch (Exception e) {
Assert.assertTrue(e instanceof XAException);
Assert.assertEquals(errorCode, ((XAException) e).errorCode);
}
}
public static byte getSamplebyte(final long position) {
return (byte) ('a' + position % ('z' - 'a' + 1));
}
// Creates a Fake LargeStream without using a real file
public static InputStream createFakeLargeStream(final long size) throws Exception {
return new InputStream() {
private long count;
private boolean closed = false;
@Override
public void close() throws IOException {
super.close();
closed = true;
}
@Override
public int read() throws IOException {
if (closed) {
throw new IOException("Stream was closed");
}
if (count++ < size) {
return getSamplebyte(count - 1);
} else {
return -1;
}
}
};
}
/**
* It validates a Bean (POJO) using simple setters and getters with random values.
* You can pass a list of properties to be ignored, as some properties will have a pre-defined domain (not being possible to use random-values on them)
*/
protected void validateGettersAndSetters(final Object pojo, final String... ignoredProperties) throws Exception {
HashSet<String> ignoreSet = new HashSet<>();
for (String ignore : ignoredProperties) {
ignoreSet.add(ignore);
}
BeanInfo info = Introspector.getBeanInfo(pojo.getClass());
PropertyDescriptor[] properties = info.getPropertyDescriptors();
for (PropertyDescriptor prop : properties) {
Object value;
if (prop.getPropertyType() == String.class) {
value = RandomUtil.randomString();
} else if (prop.getPropertyType() == Integer.class || prop.getPropertyType() == Integer.TYPE) {
value = RandomUtil.randomInt();
} else if (prop.getPropertyType() == Long.class || prop.getPropertyType() == Long.TYPE) {
value = RandomUtil.randomLong();
} else if (prop.getPropertyType() == Boolean.class || prop.getPropertyType() == Boolean.TYPE) {
value = RandomUtil.randomBoolean();
} else if (prop.getPropertyType() == Double.class || prop.getPropertyType() == Double.TYPE) {
value = RandomUtil.randomDouble();
} else {
System.out.println("Can't validate property of type " + prop.getPropertyType() + " on " + prop.getName());
value = null;
}
if (value != null && prop.getWriteMethod() != null && prop.getReadMethod() == null) {
System.out.println("WriteOnly property " + prop.getName() + " on " + pojo.getClass());
} else if (value != null && prop.getWriteMethod() != null &&
prop.getReadMethod() != null &&
!ignoreSet.contains(prop.getName())) {
System.out.println("Validating " + prop.getName() + " type = " + prop.getPropertyType());
prop.getWriteMethod().invoke(pojo, value);
Assert.assertEquals("Property " + prop.getName(), value, prop.getReadMethod().invoke(pojo));
}
}
}
/**
* @param queue
* @throws InterruptedException
*/
protected void waitForNotPaging(Queue queue) throws InterruptedException {
waitForNotPaging(queue.getPageSubscription().getPagingStore());
}
protected void waitForNotPaging(PagingStore store) throws InterruptedException {
long timeout = System.currentTimeMillis() + 20000;
while (timeout > System.currentTimeMillis() && store.isPaging()) {
Thread.sleep(100);
}
assertFalse(store.isPaging());
}
protected Topology waitForTopology(final ActiveMQServer server, final int nodes) throws Exception {
return waitForTopology(server, nodes, -1, WAIT_TIMEOUT);
}
protected Topology waitForTopology(final ActiveMQServer server,
final int nodes,
final int backups) throws Exception {
return waitForTopology(server, nodes, backups, WAIT_TIMEOUT);
}
protected Topology waitForTopology(final ActiveMQServer server,
final int liveNodes,
final int backupNodes,
final long timeout) throws Exception {
logger.debug("waiting for " + liveNodes + " on the topology for server = " + server);
long start = System.currentTimeMillis();
Set<ClusterConnection> ccs = server.getClusterManager().getClusterConnections();
if (ccs.size() != 1) {
throw new IllegalStateException("You need a single cluster connection on this version of waitForTopology on ServiceTestBase");
}
Topology topology = server.getClusterManager().getDefaultConnection(null).getTopology();
int liveNodesCount = 0;
int backupNodesCount = 0;
do {
liveNodesCount = 0;
backupNodesCount = 0;
for (TopologyMemberImpl member : topology.getMembers()) {
if (member.getLive() != null) {
liveNodesCount++;
}
if (member.getBackup() != null) {
backupNodesCount++;
}
}
if ((liveNodes == -1 || liveNodes == liveNodesCount) && (backupNodes == -1 || backupNodes == backupNodesCount)) {
return topology;
}
Thread.sleep(10);
} while (System.currentTimeMillis() - start < timeout);
String msg = "Timed out waiting for cluster topology of live=" + liveNodes + ",backup=" + backupNodes +
" (received live=" + liveNodesCount + ", backup=" + backupNodesCount +
") topology = " +
topology.describe() +
")";
ActiveMQServerLogger.LOGGER.error(msg);
throw new Exception(msg);
}
protected void waitForTopology(final ActiveMQServer server,
String clusterConnectionName,
final int nodes,
final long timeout) throws Exception {
logger.debug("waiting for " + nodes + " on the topology for server = " + server);
long start = System.currentTimeMillis();
ClusterConnection clusterConnection = server.getClusterManager().getClusterConnection(clusterConnectionName);
Topology topology = clusterConnection.getTopology();
do {
if (nodes == topology.getMembers().size()) {
return;
}
Thread.sleep(10);
} while (System.currentTimeMillis() - start < timeout);
String msg = "Timed out waiting for cluster topology of " + nodes +
" (received " +
topology.getMembers().size() +
") topology = " +
topology +
")";
ActiveMQServerLogger.LOGGER.error(msg);
throw new Exception(msg);
}
protected static final void waitForComponent(final ActiveMQComponent component,
final long seconds) throws InterruptedException {
long time = System.currentTimeMillis();
long toWait = seconds * 1000;
while (!component.isStarted()) {
Thread.sleep(50);
if (System.currentTimeMillis() > (time + toWait)) {
fail("component did not start within timeout of " + seconds);
}
}
}
protected static final Map<String, Object> generateParams(final int node, final boolean netty) {
Map<String, Object> params = new HashMap<>();
if (netty) {
params.put(org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants.DEFAULT_PORT + node);
} else {
params.put(org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants.SERVER_ID_PROP_NAME, node);
}
return params;
}
protected static final TransportConfiguration getNettyAcceptorTransportConfiguration(final boolean live) {
if (live) {
return new TransportConfiguration(NETTY_ACCEPTOR_FACTORY);
}
Map<String, Object> server1Params = new HashMap<>();
server1Params.put(org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants.DEFAULT_PORT + 1);
return new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, server1Params);
}
protected static final TransportConfiguration getNettyConnectorTransportConfiguration(final boolean live) {
if (live) {
return new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
}
Map<String, Object> server1Params = new HashMap<>();
server1Params.put(org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants.DEFAULT_PORT + 1);
return new TransportConfiguration(NETTY_CONNECTOR_FACTORY, server1Params);
}
protected static final TransportConfiguration createTransportConfiguration(boolean netty,
boolean acceptor,
Map<String, Object> params) {
String className;
if (netty) {
if (acceptor) {
className = NETTY_ACCEPTOR_FACTORY;
} else {
className = NETTY_CONNECTOR_FACTORY;
}
} else {
if (acceptor) {
className = INVM_ACCEPTOR_FACTORY;
} else {
className = INVM_CONNECTOR_FACTORY;
}
}
if (params == null)
params = new HashMap<>();
return new TransportConfiguration(className, params);
}
protected void waitForServerToStart(ActiveMQServer server) throws InterruptedException {
waitForServerToStart(server, true);
}
protected void waitForServerToStart(ActiveMQServer server, boolean activation) throws InterruptedException {
if (server == null)
return;
final long wait = 5000;
long timetowait = System.currentTimeMillis() + wait;
while (!server.isStarted() && System.currentTimeMillis() < timetowait) {
Thread.sleep(50);
}
if (!server.isStarted()) {
log.info(threadDump("Server didn't start"));
fail("server didn't start: " + server);
}
if (activation) {
if (!server.getHAPolicy().isBackup()) {
if (!server.waitForActivation(wait, TimeUnit.MILLISECONDS))
fail("Server didn't initialize: " + server);
}
}
}
protected void waitForServerToStop(ActiveMQServer server) throws InterruptedException {
if (server == null)
return;
final long wait = 5000;
long timetowait = System.currentTimeMillis() + wait;
while (server.isStarted() && System.currentTimeMillis() < timetowait) {
Thread.sleep(50);
}
if (server.isStarted()) {
log.info(threadDump("Server didn't start"));
fail("Server didn't start: " + server);
}
}
/**
* @param backup
*/
public static final void waitForRemoteBackupSynchronization(final ActiveMQServer backup) {
waitForRemoteBackup(null, 10, true, backup);
}
/**
* @param sessionFactoryP
* @param seconds
* @param waitForSync
* @param backup
*/
public static final void waitForRemoteBackup(ClientSessionFactory sessionFactoryP,
int seconds,
boolean waitForSync,
final ActiveMQServer backup) {
ClientSessionFactoryInternal sessionFactory = (ClientSessionFactoryInternal) sessionFactoryP;
final ActiveMQServerImpl actualServer = (ActiveMQServerImpl) backup;
final long toWait = seconds * 1000;
final long time = System.currentTimeMillis();
int loop = 0;
while (true) {
Activation activation = actualServer.getActivation();
boolean isReplicated = !backup.getHAPolicy().isSharedStore();
boolean isRemoteUpToDate = true;
if (isReplicated) {
if (activation instanceof SharedNothingBackupActivation) {
isRemoteUpToDate = backup.isReplicaSync();
} else {
//we may have already failed over and changed the Activation
if (actualServer.isStarted()) {
//let it fail a few time to have time to start stopping in the case of waiting to failback
isRemoteUpToDate = loop++ > 10;
} else {
//we could be waiting to failback or restart if the server is stopping
isRemoteUpToDate = false;
}
}
}
if ((sessionFactory == null || sessionFactory.getBackupConnector() != null) &&
(isRemoteUpToDate || !waitForSync) &&
(!waitForSync || actualServer.getBackupManager() != null && actualServer.getBackupManager().isBackupAnnounced())) {
break;
}
if (System.currentTimeMillis() > (time + toWait)) {
fail("backup started? (" + actualServer.isStarted() + "). Finished synchronizing (" +
(activation) + "). SessionFactory!=null ? " + (sessionFactory != null) +
" || sessionFactory.getBackupConnector()==" +
(sessionFactory != null ? sessionFactory.getBackupConnector() : "not-applicable"));
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
fail(e.getMessage());
}
}
}
public static final void waitForRemoteBackup(ClientSessionFactory sessionFactory, int seconds) {
ClientSessionFactoryInternal factoryInternal = (ClientSessionFactoryInternal) sessionFactory;
final long toWait = seconds * 1000;
final long time = System.currentTimeMillis();
while (true) {
if (factoryInternal.getBackupConnector() != null) {
break;
}
if (System.currentTimeMillis() > (time + toWait)) {
fail("Backup wasn't located");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
fail(e.getMessage());
}
}
}
protected final ActiveMQServer createServer(final boolean realFiles,
final Configuration configuration,
final long pageSize,
final long maxAddressSize) {
return createServer(realFiles, configuration, pageSize, maxAddressSize, (Map<String, AddressSettings>) null);
}
protected ActiveMQServer createServer(final boolean realFiles,
final Configuration configuration,
final long pageSize,
final long maxAddressSize,
final Map<String, AddressSettings> settings) {
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(configuration, realFiles));
if (settings != null) {
for (Map.Entry<String, AddressSettings> setting : settings.entrySet()) {
server.getAddressSettingsRepository().addMatch(setting.getKey(), setting.getValue());
}
}
AddressSettings defaultSetting = new AddressSettings().setPageSizeBytes(pageSize).setMaxSizeBytes(maxAddressSize).setAddressFullMessagePolicy(AddressFullMessagePolicy.PAGE);
server.getAddressSettingsRepository().addMatch("#", defaultSetting);
return server;
}
protected final ActiveMQServer createServer(final boolean realFiles,
final Configuration configuration,
final long pageSize,
final long maxAddressSize,
final Map<String, AddressSettings> settings,
StoreConfiguration.StoreType storeType) {
if (storeType == StoreConfiguration.StoreType.DATABASE) {
setDBStoreType(configuration);
}
return createServer(realFiles, configuration, pageSize, maxAddressSize, settings);
}
protected final ActiveMQServer createServer(final boolean realFiles) throws Exception {
return createServer(realFiles, false);
}
protected final ActiveMQServer createServer(final boolean realFiles, final boolean netty) throws Exception {
return createServer(realFiles, createDefaultConfig(netty), AddressSettings.DEFAULT_PAGE_SIZE, AddressSettings.DEFAULT_MAX_SIZE_BYTES);
}
protected ActiveMQServer createServer(final boolean realFiles, final Configuration configuration) {
return createServer(realFiles, configuration, AddressSettings.DEFAULT_PAGE_SIZE, AddressSettings.DEFAULT_MAX_SIZE_BYTES);
}
protected final ActiveMQServer createServer(final Configuration configuration) {
return createServer(configuration.isPersistenceEnabled(), configuration, AddressSettings.DEFAULT_PAGE_SIZE, AddressSettings.DEFAULT_MAX_SIZE_BYTES);
}
protected ActiveMQServer createServer(final boolean realFiles,
boolean isNetty,
StoreConfiguration.StoreType storeType) throws Exception {
Configuration configuration = storeType == StoreConfiguration.StoreType.DATABASE ? createDefaultJDBCConfig(isNetty) : createDefaultConfig(isNetty);
return createServer(realFiles, configuration, AddressSettings.DEFAULT_PAGE_SIZE, AddressSettings.DEFAULT_MAX_SIZE_BYTES);
}
protected ActiveMQServer createInVMFailoverServer(final boolean realFiles,
final Configuration configuration,
final NodeManager nodeManager,
final int id) {
return createInVMFailoverServer(realFiles, configuration, -1, -1, new HashMap<String, AddressSettings>(), nodeManager, id);
}
protected ActiveMQServer createInVMFailoverServer(final boolean realFiles,
final Configuration configuration,
final int pageSize,
final int maxAddressSize,
final Map<String, AddressSettings> settings,
NodeManager nodeManager,
final int id) {
ActiveMQServer server;
ActiveMQSecurityManager securityManager = new ActiveMQJAASSecurityManager(InVMLoginModule.class.getName(), new SecurityConfiguration());
configuration.setPersistenceEnabled(realFiles);
server = addServer(new InVMNodeManagerServer(configuration, ManagementFactory.getPlatformMBeanServer(), securityManager, nodeManager));
try {
server.setIdentity("Server " + id);
for (Map.Entry<String, AddressSettings> setting : settings.entrySet()) {
server.getAddressSettingsRepository().addMatch(setting.getKey(), setting.getValue());
}
AddressSettings defaultSetting = new AddressSettings();
defaultSetting.setPageSizeBytes(pageSize);
defaultSetting.setMaxSizeBytes(maxAddressSize);
server.getAddressSettingsRepository().addMatch("#", defaultSetting);
return server;
} finally {
addServer(server);
}
}
protected ActiveMQServer createColocatedInVMFailoverServer(final boolean realFiles,
final Configuration configuration,
NodeManager liveNodeManager,
NodeManager backupNodeManager,
final int id) {
return createColocatedInVMFailoverServer(realFiles, configuration, -1, -1, new HashMap<String, AddressSettings>(), liveNodeManager, backupNodeManager, id);
}
protected ActiveMQServer createColocatedInVMFailoverServer(final boolean realFiles,
final Configuration configuration,
final int pageSize,
final int maxAddressSize,
final Map<String, AddressSettings> settings,
NodeManager liveNodeManager,
NodeManager backupNodeManager,
final int id) {
ActiveMQServer server;
ActiveMQSecurityManager securityManager = new ActiveMQJAASSecurityManager(InVMLoginModule.class.getName(), new SecurityConfiguration());
configuration.setPersistenceEnabled(realFiles);
server = new ColocatedActiveMQServer(configuration, ManagementFactory.getPlatformMBeanServer(), securityManager, liveNodeManager, backupNodeManager);
try {
server.setIdentity("Server " + id);
for (Map.Entry<String, AddressSettings> setting : settings.entrySet()) {
server.getAddressSettingsRepository().addMatch(setting.getKey(), setting.getValue());
}
AddressSettings defaultSetting = new AddressSettings();
defaultSetting.setPageSizeBytes(pageSize);
defaultSetting.setMaxSizeBytes(maxAddressSize);
server.getAddressSettingsRepository().addMatch("#", defaultSetting);
return server;
} finally {
addServer(server);
}
}
protected ActiveMQServer createClusteredServerWithParams(final boolean isNetty,
final int index,
final boolean realFiles,
final Map<String, Object> params) throws Exception {
String acceptor = isNetty ? NETTY_ACCEPTOR_FACTORY : INVM_ACCEPTOR_FACTORY;
return createServer(realFiles, createDefaultConfig(index, params, acceptor), -1, -1);
}
protected ActiveMQServer createClusteredServerWithParams(final boolean isNetty,
final int index,
final boolean realFiles,
final int pageSize,
final int maxAddressSize,
final Map<String, Object> params) throws Exception {
return createServer(realFiles, createDefaultConfig(index, params, (isNetty ? NETTY_ACCEPTOR_FACTORY : INVM_ACCEPTOR_FACTORY)), pageSize, maxAddressSize);
}
protected ServerLocator createFactory(final boolean isNetty) throws Exception {
if (isNetty) {
return createNettyNonHALocator();
} else {
return createInVMNonHALocator();
}
}
protected void createQueue(final String address, final String queue) throws Exception {
ServerLocator locator = createInVMNonHALocator();
ClientSessionFactory sf = locator.createSessionFactory();
ClientSession session = sf.createSession();
try {
session.createQueue(address, queue);
} finally {
session.close();
closeSessionFactory(sf);
closeServerLocator(locator);
}
}
protected final ServerLocator createInVMLocator(final int serverID) {
TransportConfiguration tnspConfig = createInVMTransportConnectorConfig(serverID, UUIDGenerator.getInstance().generateStringUUID());
ServerLocator locator = ActiveMQClient.createServerLocatorWithHA(tnspConfig);
return addServerLocator(locator);
}
/**
* @param serverID
* @return
*/
protected final TransportConfiguration createInVMTransportConnectorConfig(final int serverID, String name1) {
Map<String, Object> server1Params = new HashMap<>();
if (serverID != 0) {
server1Params.put(TransportConstants.SERVER_ID_PROP_NAME, serverID);
}
TransportConfiguration tnspConfig = new TransportConfiguration(INVM_CONNECTOR_FACTORY, server1Params, name1);
return tnspConfig;
}
public String getTextMessage(final ClientMessage m) {
m.getBodyBuffer().resetReaderIndex();
return m.getBodyBuffer().readString();
}
protected ClientMessage createBytesMessage(final ClientSession session,
final byte type,
final byte[] b,
final boolean durable) {
ClientMessage message = session.createMessage(type, durable, 0, System.currentTimeMillis(), (byte) 1);
message.getBodyBuffer().writeBytes(b);
return message;
}
/**
* @param i
* @param message
* @throws Exception
*/
protected void setBody(final int i, final ClientMessage message) {
message.getBodyBuffer().writeString("message" + i);
}
/**
* @param i
* @param message
*/
protected void assertMessageBody(final int i, final ClientMessage message) {
Assert.assertEquals(message.toString(), "message" + i, message.getBodyBuffer().readString());
}
/**
* Send durable messages with pre-specified body.
*
* @param session
* @param producer
* @param numMessages
* @throws Exception
*/
public final void sendMessages(ClientSession session,
ClientProducer producer,
int numMessages) throws ActiveMQException {
for (int i = 0; i < numMessages; i++) {
producer.send(createMessage(session, i, true));
}
}
protected final ClientMessage createMessage(ClientSession session,
int counter,
boolean durable) throws ActiveMQException {
ClientMessage message = session.createMessage(durable);
setBody(counter, message);
message.putIntProperty("counter", counter);
message.putIntProperty(SEND_CALL_NUMBER, sendMsgCount++);
return message;
}
protected final void receiveMessages(ClientConsumer consumer,
final int start,
final int msgCount,
final boolean ack) throws ActiveMQException {
for (int i = start; i < msgCount; i++) {
ClientMessage message = consumer.receive(1000);
Assert.assertNotNull("Expecting a message " + i, message);
// sendCallNumber is just a debugging measure.
Object prop = message.getObjectProperty(SEND_CALL_NUMBER);
if (prop == null)
prop = Integer.valueOf(-1);
final int actual = message.getIntProperty("counter").intValue();
Assert.assertEquals("expected=" + i + ". Got: property['counter']=" + actual + " sendNumber=" + prop, i, actual);
assertMessageBody(i, message);
if (ack)
message.acknowledge();
}
}
/**
* Reads a journal system and returns a Map<Integer,AtomicInteger> of recordTypes and the number of records per type,
* independent of being deleted or not
*
* @param config
* @return
* @throws Exception
*/
protected Pair<List<RecordInfo>, List<PreparedTransactionInfo>> loadMessageJournal(Configuration config) throws Exception {
JournalImpl messagesJournal = null;
try {
SequentialFileFactory messagesFF = new NIOSequentialFileFactory(new File(getJournalDir()), null, 1);
messagesJournal = new JournalImpl(config.getJournalFileSize(), config.getJournalMinFiles(), config.getJournalPoolFiles(), 0, 0, messagesFF, "activemq-data", "amq", 1);
final List<RecordInfo> committedRecords = new LinkedList<>();
final List<PreparedTransactionInfo> preparedTransactions = new LinkedList<>();
messagesJournal.start();
messagesJournal.load(committedRecords, preparedTransactions, null, false);
return new Pair<>(committedRecords, preparedTransactions);
} finally {
try {
if (messagesJournal != null) {
messagesJournal.stop();
}
} catch (Throwable ignored) {
}
}
}
/**
* Reads a journal system and returns a Map<Integer,AtomicInteger> of recordTypes and the number of records per type,
* independent of being deleted or not
*
* @param config
* @return
* @throws Exception
*/
protected HashMap<Integer, AtomicInteger> countJournal(Configuration config) throws Exception {
final HashMap<Integer, AtomicInteger> recordsType = new HashMap<>();
SequentialFileFactory messagesFF = new NIOSequentialFileFactory(config.getJournalLocation(), null, 1);
JournalImpl messagesJournal = new JournalImpl(config.getJournalFileSize(), config.getJournalMinFiles(), config.getJournalPoolFiles(), 0, 0, messagesFF, "activemq-data", "amq", 1);
List<JournalFile> filesToRead = messagesJournal.orderFiles();
for (JournalFile file : filesToRead) {
JournalImpl.readJournalFile(messagesFF, file, new RecordTypeCounter(recordsType));
}
return recordsType;
}
/**
* This method will load a journal and count the living records
*
* @param config
* @return
* @throws Exception
*/
protected HashMap<Integer, AtomicInteger> countJournalLivingRecords(Configuration config) throws Exception {
return internalCountJournalLivingRecords(config, true);
}
/**
* This method will load a journal and count the living records
*
* @param config
* @param messageJournal if true -> MessageJournal, false -> BindingsJournal
* @return
* @throws Exception
*/
protected HashMap<Integer, AtomicInteger> internalCountJournalLivingRecords(Configuration config,
boolean messageJournal) throws Exception {
final HashMap<Integer, AtomicInteger> recordsType = new HashMap<>();
SequentialFileFactory ff;
JournalImpl journal;
if (messageJournal) {
ff = new NIOSequentialFileFactory(config.getJournalLocation(), null, 1);
journal = new JournalImpl(config.getJournalFileSize(), config.getJournalMinFiles(), config.getJournalPoolFiles(), 0, 0, ff, "activemq-data", "amq", 1);
} else {
ff = new NIOSequentialFileFactory(config.getBindingsLocation(), null, 1);
journal = new JournalImpl(1024 * 1024, 2, config.getJournalCompactMinFiles(), config.getJournalPoolFiles(), config.getJournalCompactPercentage(), ff, "activemq-bindings", "bindings", 1);
}
journal.start();
final List<RecordInfo> committedRecords = new LinkedList<>();
final List<PreparedTransactionInfo> preparedTransactions = new LinkedList<>();
journal.load(committedRecords, preparedTransactions, null, false);
for (RecordInfo info : committedRecords) {
Integer ikey = new Integer(info.getUserRecordType());
AtomicInteger value = recordsType.get(ikey);
if (value == null) {
value = new AtomicInteger();
recordsType.put(ikey, value);
}
value.incrementAndGet();
}
journal.stop();
return recordsType;
}
private static final class RecordTypeCounter implements JournalReaderCallback {
private final HashMap<Integer, AtomicInteger> recordsType;
/**
* @param recordsType
*/
private RecordTypeCounter(HashMap<Integer, AtomicInteger> recordsType) {
this.recordsType = recordsType;
}
AtomicInteger getType(byte key) {
if (key == 0) {
System.out.println("huh?");
}
Integer ikey = new Integer(key);
AtomicInteger value = recordsType.get(ikey);
if (value == null) {
value = new AtomicInteger();
recordsType.put(ikey, value);
}
return value;
}
@Override
public void onReadUpdateRecordTX(long transactionID, RecordInfo recordInfo) throws Exception {
getType(recordInfo.getUserRecordType()).incrementAndGet();
}
@Override
public void onReadUpdateRecord(RecordInfo recordInfo) throws Exception {
getType(recordInfo.getUserRecordType()).incrementAndGet();
}
@Override
public void onReadAddRecordTX(long transactionID, RecordInfo recordInfo) throws Exception {
getType(recordInfo.getUserRecordType()).incrementAndGet();
}
@Override
public void onReadAddRecord(RecordInfo recordInfo) throws Exception {
getType(recordInfo.getUserRecordType()).incrementAndGet();
}
@Override
public void onReadRollbackRecord(long transactionID) throws Exception {
}
@Override
public void onReadPrepareRecord(long transactionID, byte[] extraData, int numberOfRecords) throws Exception {
}
@Override
public void onReadDeleteRecordTX(long transactionID, RecordInfo recordInfo) throws Exception {
}
@Override
public void onReadDeleteRecord(long recordID) throws Exception {
}
@Override
public void onReadCommitRecord(long transactionID, int numberOfRecords) throws Exception {
}
@Override
public void markAsDataFile(JournalFile file0) {
}
}
/**
* @param server the server where's being checked
* @param address the name of the address being checked
* @param local if true we are looking for local bindings, false we are looking for remoting servers
* @param expectedBindingCount the expected number of counts
* @param expectedConsumerCount the expected number of consumers
* @param timeout the timeout used on the check
* @return
* @throws Exception
* @throws InterruptedException
*/
protected boolean waitForBindings(final ActiveMQServer server,
final String address,
final boolean local,
final int expectedBindingCount,
final int expectedConsumerCount,
long timeout) throws Exception {
final PostOffice po = server.getPostOffice();
long start = System.currentTimeMillis();
int bindingCount = 0;
int totConsumers = 0;
do {
bindingCount = 0;
totConsumers = 0;
Bindings bindings = po.getBindingsForAddress(new SimpleString(address));
for (Binding binding : bindings.getBindings()) {
if (binding.isConnected() && (binding instanceof LocalQueueBinding && local || binding instanceof RemoteQueueBinding && !local)) {
QueueBinding qBinding = (QueueBinding) binding;
bindingCount++;
totConsumers += qBinding.consumerCount();
}
}
if (bindingCount == expectedBindingCount && totConsumers == expectedConsumerCount) {
return true;
}
Thread.sleep(10);
} while (System.currentTimeMillis() - start < timeout);
String msg = "Timed out waiting for bindings (bindingCount = " + bindingCount +
" (expecting " +
expectedBindingCount +
") " +
", totConsumers = " +
totConsumers +
" (expecting " +
expectedConsumerCount +
")" +
")";
log.error(msg);
return false;
}
/**
* Deleting a file on LargeDir is an asynchronous process. We need to keep looking for a while if
* the file hasn't been deleted yet.
*/
protected void validateNoFilesOnLargeDir(final String directory, final int expect) throws Exception {
File largeMessagesFileDir = new File(directory);
// Deleting the file is async... we keep looking for a period of the time until the file is really gone
long timeout = System.currentTimeMillis() + 5000;
while (timeout > System.currentTimeMillis() && largeMessagesFileDir.listFiles().length != expect) {
Thread.sleep(100);
}
if (expect != largeMessagesFileDir.listFiles().length) {
for (File file : largeMessagesFileDir.listFiles()) {
System.out.println("File " + file + " still on ");
}
}
Assert.assertEquals(expect, largeMessagesFileDir.listFiles().length);
}
/**
* Deleting a file on LargeDire is an asynchronous process. Wee need to keep looking for a while
* if the file hasn't been deleted yet
*/
protected void validateNoFilesOnLargeDir() throws Exception {
validateNoFilesOnLargeDir(getLargeMessagesDir(), 0);
}
public void printBindings(ActiveMQServer server, String address) throws Exception {
PostOffice po = server.getPostOffice();
Bindings bindings = po.getBindingsForAddress(new SimpleString(address));
System.err.println("=======================================================================");
System.err.println("Binding information for address = " + address + " for server " + server);
for (Binding binding : bindings.getBindings()) {
QueueBinding qBinding = (QueueBinding) binding;
System.err.println("Binding = " + qBinding + ", queue=" + qBinding.getQueue());
}
}
private void assertAllExecutorsFinished() throws InterruptedException {
for (ExecutorService s : executorSet) {
Assert.assertTrue(s.awaitTermination(5, TimeUnit.SECONDS));
}
}
private ArrayList<Exception> checkCsfStopped() {
long time = System.currentTimeMillis();
long waitUntil = time + 5000;
while (!ClientSessionFactoryImpl.CLOSE_RUNNABLES.isEmpty() && time < waitUntil) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
//ignore
}
time = System.currentTimeMillis();
}
List<ClientSessionFactoryImpl.CloseRunnable> closeRunnables = new ArrayList<>(ClientSessionFactoryImpl.CLOSE_RUNNABLES);
ArrayList<Exception> exceptions = new ArrayList<>();
if (!closeRunnables.isEmpty()) {
for (ClientSessionFactoryImpl.CloseRunnable closeRunnable : closeRunnables) {
if (closeRunnable != null) {
exceptions.add(closeRunnable.stop().createTrace);
}
}
}
return exceptions;
}
private void assertAllClientProducersAreClosed() {
synchronized (clientProducers) {
for (ClientProducer p : clientProducers) {
assertTrue(p + " should be closed", p.isClosed());
}
clientProducers.clear();
}
}
/**
*
*/
private void closeAllOtherComponents() {
synchronized (otherComponents) {
for (ActiveMQComponent c : otherComponents) {
stopComponent(c);
}
otherComponents.clear();
}
}
private void checkFilesUsage() {
long timeout = System.currentTimeMillis() + 15000;
while (LibaioContext.getTotalMaxIO() != 0 && System.currentTimeMillis() > timeout) {
try {
Thread.sleep(100);
} catch (Exception ignored) {
}
}
int invmSize = InVMRegistry.instance.size();
if (invmSize > 0) {
InVMRegistry.instance.clear();
log.info(threadDump("Thread dump"));
fail("invm registry still had acceptors registered");
}
final long totalMaxIO = LibaioContext.getTotalMaxIO();
if (totalMaxIO != 0) {
LibaioContext.resetMaxAIO();
Assert.fail("test did not close all its files " + totalMaxIO);
}
}
private void cleanupPools() {
OperationContextImpl.clearContext();
// We shutdown the global pools to give a better isolation between tests
try {
ServerLocatorImpl.clearThreadPools();
} catch (Throwable e) {
log.info(threadDump(e.getMessage()));
System.err.println(threadDump(e.getMessage()));
}
try {
NettyConnector.clearThreadPools();
} catch (Exception e) {
log.info(threadDump(e.getMessage()));
System.err.println(threadDump(e.getMessage()));
}
}
protected static final void recreateDirectory(final String directory) {
File file = new File(directory);
deleteDirectory(file);
file.mkdirs();
}
protected static final boolean deleteDirectory(final File directory) {
return FileUtil.deleteDirectory(directory);
}
protected static final void copyRecursive(final File from, final File to) throws Exception {
if (from.isDirectory()) {
if (!to.exists()) {
to.mkdir();
}
String[] subs = from.list();
for (String sub : subs) {
copyRecursive(new File(from, sub), new File(to, sub));
}
} else {
try (InputStream in = new BufferedInputStream(new FileInputStream(from));
OutputStream out = new BufferedOutputStream(new FileOutputStream(to))) {
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
}
}
}
protected void assertRefListsIdenticalRefs(final List<MessageReference> l1, final List<MessageReference> l2) {
if (l1.size() != l2.size()) {
Assert.fail("Lists different sizes: " + l1.size() + ", " + l2.size());
}
Iterator<MessageReference> iter1 = l1.iterator();
Iterator<MessageReference> iter2 = l2.iterator();
while (iter1.hasNext()) {
MessageReference o1 = iter1.next();
MessageReference o2 = iter2.next();
Assert.assertTrue("expected " + o1 + " but was " + o2, o1 == o2);
}
}
protected Message generateMessage(final long id) {
ICoreMessage message = new CoreMessage(id, 1000);
message.setMessageID(id);
message.getBodyBuffer().writeString(UUID.randomUUID().toString());
message.setAddress(new SimpleString("foo"));
return message;
}
protected MessageReference generateReference(final Queue queue, final long id) {
Message message = generateMessage(id);
return MessageReference.Factory.createReference(message, queue);
}
protected int calculateRecordSize(final int size, final int alignment) {
return (size / alignment + (size % alignment != 0 ? 1 : 0)) * alignment;
}
protected ClientMessage createTextMessage(final ClientSession session, final String s) {
return createTextMessage(session, s, true);
}
protected ClientMessage createTextMessage(final ClientSession session, final String s, final boolean durable) {
ClientMessage message = session.createMessage(Message.TEXT_TYPE, durable, 0, System.currentTimeMillis(), (byte) 4);
message.getBodyBuffer().writeString(s);
return message;
}
protected XidImpl newXID() {
return new XidImpl("xa1".getBytes(), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes());
}
protected int getMessageCount(final ActiveMQServer service, final String address) throws Exception {
return getMessageCount(service.getPostOffice(), address);
}
/**
* @param address
* @param postOffice
* @return
* @throws Exception
*/
protected int getMessageCount(final PostOffice postOffice, final String address) throws Exception {
int messageCount = 0;
List<QueueBinding> bindings = getLocalQueueBindings(postOffice, address);
for (QueueBinding qBinding : bindings) {
qBinding.getQueue().flushExecutor();
messageCount += getMessageCount(qBinding.getQueue());
}
return messageCount;
}
protected int getMessageCount(final Queue queue) {
queue.flushExecutor();
return (int) queue.getMessageCount();
}
protected int getMessagesAdded(final Queue queue) {
queue.flushExecutor();
return (int) queue.getMessagesAdded();
}
private List<QueueBinding> getLocalQueueBindings(final PostOffice postOffice,
final String address) throws Exception {
ArrayList<QueueBinding> bindingsFound = new ArrayList<>();
Bindings bindings = postOffice.getBindingsForAddress(new SimpleString(address));
for (Binding binding : bindings.getBindings()) {
if (binding instanceof LocalQueueBinding) {
bindingsFound.add((QueueBinding) binding);
}
}
return bindingsFound;
}
protected final ServerLocator createInVMNonHALocator() {
return createNonHALocator(false);
}
protected final ServerLocator createNettyNonHALocator() {
return createNonHALocator(true);
}
protected final ServerLocator createNonHALocator(final boolean isNetty) {
ServerLocator locatorWithoutHA = internalCreateNonHALocator(isNetty);
return addServerLocator(locatorWithoutHA);
}
/**
* Creates the Locator without adding it to the list where the tearDown will take place
* This is because we don't want it closed in certain tests where we are issuing failures
*
* @param isNetty
* @return
*/
public ServerLocator internalCreateNonHALocator(boolean isNetty) {
return isNetty ? ActiveMQClient.createServerLocatorWithoutHA(new TransportConfiguration(NETTY_CONNECTOR_FACTORY)) : ActiveMQClient.createServerLocatorWithoutHA(new TransportConfiguration(INVM_CONNECTOR_FACTORY));
}
protected static final void stopComponent(ActiveMQComponent component) {
if (component == null)
return;
try {
component.stop();
} catch (Exception e) {
// no-op
}
}
protected static final void stopComponentOutputExceptions(ActiveMQComponent component) {
if (component == null)
return;
try {
component.stop();
} catch (Exception e) {
System.err.println("Exception closing " + component);
e.printStackTrace();
}
}
protected final ClientSessionFactory createSessionFactory(ServerLocator locator) throws Exception {
ClientSessionFactory sf = locator.createSessionFactory();
addSessionFactory(sf);
return sf;
}
protected final ActiveMQServer addServer(final ActiveMQServer server) {
if (server != null) {
synchronized (servers) {
servers.add(server);
}
}
return server;
}
protected final ServerLocator addServerLocator(final ServerLocator locator) {
if (locator != null) {
synchronized (locators) {
locators.add(locator);
}
}
return locator;
}
protected final ClientSession addClientSession(final ClientSession session) {
if (session != null) {
synchronized (clientSessions) {
clientSessions.add(session);
}
}
return session;
}
protected final ClientConsumer addClientConsumer(final ClientConsumer consumer) {
if (consumer != null) {
synchronized (clientConsumers) {
clientConsumers.add(consumer);
}
}
return consumer;
}
protected final ClientProducer addClientProducer(final ClientProducer producer) {
if (producer != null) {
synchronized (clientProducers) {
clientProducers.add(producer);
}
}
return producer;
}
protected final void addActiveMQComponent(final ActiveMQComponent component) {
if (component != null) {
synchronized (otherComponents) {
otherComponents.add(component);
}
}
}
protected final ClientSessionFactory addSessionFactory(final ClientSessionFactory sf) {
if (sf != null) {
synchronized (sessionFactories) {
sessionFactories.add(sf);
}
}
return sf;
}
private void assertAllClientConsumersAreClosed() {
synchronized (clientConsumers) {
for (ClientConsumer cc : clientConsumers) {
if (cc == null)
continue;
assertTrue(cc.isClosed());
}
clientConsumers.clear();
}
}
private void assertAllClientSessionsAreClosed() {
synchronized (clientSessions) {
for (final ClientSession cs : clientSessions) {
if (cs == null)
continue;
assertTrue(cs.isClosed());
}
clientSessions.clear();
}
}
protected void closeAllSessionFactories() {
synchronized (sessionFactories) {
for (ClientSessionFactory sf : sessionFactories) {
if (!sf.isClosed()) {
closeSessionFactory(sf);
assert sf.isClosed();
}
}
sessionFactories.clear();
}
}
protected void closeAllServerLocatorsFactories() {
synchronized (locators) {
for (ServerLocator locator : locators) {
closeServerLocator(locator);
}
locators.clear();
}
}
public static final void closeServerLocator(ServerLocator locator) {
if (locator == null)
return;
try {
locator.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static final void closeSessionFactory(final ClientSessionFactory sf) {
if (sf == null)
return;
try {
sf.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void crashAndWaitForFailure(ActiveMQServer server, ClientSession... sessions) throws Exception {
CountDownLatch latch = new CountDownLatch(sessions.length);
for (ClientSession session : sessions) {
CountDownSessionFailureListener listener = new CountDownSessionFailureListener(latch, session);
session.addFailureListener(listener);
}
ClusterManager clusterManager = server.getClusterManager();
clusterManager.flushExecutor();
clusterManager.clear();
Assert.assertTrue("server should be running!", server.isStarted());
server.stop(true);
if (sessions.length > 0) {
// Wait to be informed of failure
boolean ok = latch.await(10000, TimeUnit.MILLISECONDS);
Assert.assertTrue("Failed to stop the server! Latch count is " + latch.getCount() + " out of " +
sessions.length, ok);
}
}
public static void crashAndWaitForFailure(ActiveMQServer server, ServerLocator locator) throws Exception {
ClientSessionFactory sf = locator.createSessionFactory();
ClientSession session = sf.createSession();
try {
crashAndWaitForFailure(server, session);
} finally {
try {
session.close();
sf.close();
} catch (Exception ignored) {
}
}
}
public interface RunnerWithEX {
void run() throws Throwable;
}
// This can be used to interrupt a thread if it takes more than timeoutMilliseconds
public boolean runWithTimeout(final RunnerWithEX runner, final long timeoutMilliseconds) throws Throwable {
class ThreadRunner extends Thread {
Throwable t;
final RunnerWithEX run;
ThreadRunner(RunnerWithEX run) {
this.run = run;
}
@Override
public void run() {
try {
runner.run();
} catch (Throwable t) {
this.t = t;
}
}
}
ThreadRunner runnerThread = new ThreadRunner(runner);
runnerThread.start();
boolean hadToInterrupt = false;
while (runnerThread.isAlive()) {
runnerThread.join(timeoutMilliseconds);
if (runnerThread.isAlive()) {
System.err.println("Thread still running, interrupting it now:");
for (Object t : runnerThread.getStackTrace()) {
System.err.println(t);
}
hadToInterrupt = true;
runnerThread.interrupt();
}
}
if (runnerThread.t != null) {
runnerThread.t.printStackTrace();
throw runnerThread.t;
}
// we are returning true if it ran ok.
// had to Interrupt is exactly the opposite of what we are returning
return !hadToInterrupt;
}
// Private -------------------------------------------------------
// Inner classes -------------------------------------------------
protected interface ActiveMQAction {
void run() throws Exception;
}
/**
* Asserts that latch completes within a (rather large interval).
* <p>
* Use this instead of just calling {@code latch.await()}. Otherwise your test may hang the whole
* test run if it fails to count-down the latch.
*
* @param latch
* @throws InterruptedException
*/
public static void waitForLatch(CountDownLatch latch) throws InterruptedException {
assertTrue("Latch has got to return within a minute", latch.await(1, TimeUnit.MINUTES));
}
}